vue基础教程
渐进式JavaScript
框架
作者: 尤雨溪
特点
- 遵循
MVVM
- 编码简洁, 体积小, 运行效率高, 适合移动/PC端开发
- 它本身只关注UI, 也可以引入其它第三方库开发
- 借鉴
Angular
的模板和数据绑定技术 - 借鉴
React
的组件化和虚拟DOM
技术
Vue周边库
- vue-cli: vue 脚手架
- vue-resource
- axios
- vue-router: 路由
- vuex: 状态管理
- element-ui: 基于vue的UI组件库(PC端)
环境准备
可以参考官方文档
- 浏览器安装
vue-devtools
插件浏览器开发者插件如果chrome浏览器下载不了插件建议使用edge浏览器可以直接下载这个插件
- 开发工具选择vscode 参考vscode安装_扩展安装 vscode前端插件
按照惯例写一个Hello World
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../xx/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="demo">
<h1>Hello,{{name.toUpperCase()}},{{address}}</h1>
</div>
<script type="text/javascript" >
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
//创建Vue实例
new Vue({
el:'#demo', //el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串。
data:{ //data中用于存储数据,数据供el所指定的容器去使用,值我们暂时先写成一个对象。
name:'vue',
address:'深圳'
}
})
</script>
</body>
</html>
MVVM模型
vue的灵感来自MVVM模型,可以按如下图方式理解
说明:
- M:模型(Model) :data中的数据
- V:视图(View) :模板代码
- VM:视图模型(ViewModel):Vue实例
模板语法
Vue
使用一种基于HTML
的模板语法,使我们能够声明式地将其组件实例的数据绑定到呈现的DOM
上。所有的Vue
模板都是语法层面合法的HTML
,可以被符合规范的浏览器和 HTML
解析器解析。
在底层机制中,Vue
会将模板编译成高度优化的JavaScript
代码。结合响应式系统,当应用状态变更时,Vue
能够智能地推导出需要重新渲染的组件的最少数量,并应用最少的DOM
操作。
Vue模板语法有2大类:
- 插值语法:
- 功能:用于解析标签体内容。
- 写法:
{{xxx}}
,xxx
是js
表达式,且可以直接读取到data
中的所有属性
- 指令语法:
- 功能:用于解析标签(包括:标签属性、标签体内容、绑定事件.....)。
- 举例:
v-bind:href="xxx"
或 简写为:href="xxx"
,xxx
同样要写js
表达式,且可以直接读取到data
中的所有属性。 - 备注:Vue中有很多的指令,且形式都是:
v-????
,此处我们只是拿v-bind
举个例子
数据绑定
- 单向绑定(
v-bind
):数据只能从data
流向页面 - 双向绑定(
v-model
):数据不仅能从data
流向页面,还可以从页面流向data
- 双向绑定一般都应用在表单类元素上(如:
input
、select
等)v-model:value
可以简写为v-model
,因为v-model
默认收集的就是value值
<input type="text" v-model="name"><br/>
数据代理
底层原理Object.defineProperty
方法
-
Vue中的数据代理:
通过vm对象来代理data对象中属性的操作(读/写)
-
Vue中数据代理的好处:
更加方便的操作data中的数据
-
基本原理:
通过
Object.defineProperty()
把data
对象中所有属性添加到vm上
为每一个添加到vm上的属性,都指定一个getter/setter
在getter/setter
内部去操作(读/写)data
中对应的属性
let person = {
name:'张三',
sex:'男',
}
let age = 18
Object.defineProperty(person,'age',{
// enumerable:true, //控制属性是否可以枚举,默认值是false
// writable:true, //控制属性是否可以被修改,默认值是false
// configurable:true //控制属性是否可以被删除,默认值是false
//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
get(){
console.log('有人读取age属性了')
return age
},
//当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
set(value){
console.log('有人修改了age属性,且值是', value)
age = value
}
})
事件处理
- 使用
v-on:xxx
或@xxx
绑定事件,其中xxx
是事件名 - 事件的回调需要配置在
methods
对象中,最终会在vm
上 methods中
配置的函数,不要用箭头函数!否则this
就不是vm
了methods
中配置的函数,都是被Vue
所管理的函数,this
的指向是vm
或组件实例对象@click="demo"
和@click="demo($event)"
效果一致,但后者可以传参
Vue中的事件修饰符
- prevent:阻止默认事件(常用)
- stop:阻止事件冒泡(常用)
- once:事件只触发一次(常用)
- capture:使用事件的捕获模式
- self:只有event.target是当前操作的元素时才触发事件
- passive:事件的默认行为立即执行,无需等待事件回调执行完毕
键盘事件
-
Vue中常用的按键别名
回车 => enter
删除 => delete (捕获“删除”和“退格”键)
退出 => esc
空格 => space
换行 => tab (特殊,必须配合keydown去使用)
上 => up
下 => down
左 => left
右 => right -
Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)
-
系统修饰键(用法特殊):
ctrl
、alt
、shift
、meta
- 配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发,例如
@keydown.ctrl.y
- 配合keydown使用:正常触发事件
- 配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发,例如
-
也可以使用keyCode去指定具体的按键(不推荐)
-
Vue.config.keyCodes.自定义键名 = 键码
,可以去定制按键别名
计算属性
- 定义:要用的属性不存在,要通过已有属性计算得来
- 原理:底层借助了
Objcet.defineproperty
方法提供的getter
和setter
get
函数什么时候执行- 初次读取时会执行一次
- 当依赖的数据发生改变时会被再次调用
- 优势:与
methods
实现相比,内部有缓存机制(复用),效率更高,调试方便 - 备注:
- 计算属性最终会出现在vm上,直接读取使用即可
- 如果计算属性要被修改,那必须写
setter
函数去响应修改,且setter
中要引起计算时依赖的数据发生改变
示例代码:
new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三',
},
computed:{
fullName:{
// fullName是计算属性最完整的写法
//get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
//get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
get(){
console.log('get被调用了')
// console.log(this) //此处的this是vm
return this.firstName + '-' + this.lastName
},
//set什么时候调用? 当fullName被修改时。
set(value){
console.log('set',value)
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
},
// fullName(){
// // fullName是计算属性的简写形式,是一个方法,相当于完整写法的get方法
// console.log('get被调用了')
// return this.firstName + '-' + this.lastName
// }
}
})
监视属性watch
- 当被监视的属性变化时, 回调函数自动调用, 进行相关操作
- 监视的属性必须存在,才能进行监视!!
- 监视的两种写法:
- new Vue时传入watch配置
- 通过vm.$watch监视
示例代码:
const vm = new Vue({
el:'#root',
data:{
isHot:true,
},
// new Vue时传入watch配置
watch:{
isHot:{
immediate: false, //true:初始化时让handler调用一下, false:初始化时不调用handler
//handler什么时候调用?当isHot发生改变时。
handler(newValue, oldValue){
console.log('isHot被修改了', newValue, oldValue)
}
}
// 简写方式,直接是一个函数
// isHot(newValue, oldValue){
// console.log('isHot被修改了',newValue,oldValue,this)
// }
}
})
// 通过vm.$watch监视
vm.$watch('isHot',{
immediate: true, //初始化时让handler调用一下
//handler什么时候调用?当isHot发生改变时。
handler(newValue, oldValue){
console.log('isHot被修改了,by$watch', newValue, oldValue)
}
})
深度监视
- Vue中的
watch
默认不监测对象内部值的改变(一层) - 配置
deep:true
可以监测对象内部值改变(多层) - 使用
watch
时根据数据的具体结构,决定是否采用深度监视
示例代码:
const vm = new Vue({
el: '#root',
data: {
isHot: true,
numbers: {
a: 1,
b: 1,
c: {
d: {
e: 100
}
}
}
},
methods: {
changeWeather() {
// 修改属性
this.isHot = !this.isHot
}
},
watch: {
isHot: {
// immediate: true, //初始化时让handler调用一下
//handler什么时候调用?当isHot发生改变时。
handler(newValue, oldValue) {
console.log('isHot被修改了', newValue, oldValue)
}
},
//监视多级结构中某个属性的变化
/* 'numbers.a':{
handler(){
console.log('a被改变了')
}
} */
//监视多级结构中所有属性的变化
numbers: {
// deep:true 可以监测对象内部值改变
deep: true,
handler() {
console.log('numbers改变了')
}
}
}
})
总结计算属性与检测属性
- computed和watch之间的区别:
computed
能完成的功能,watch
都可以完成watch
能完成的功能,computed
不一定能完成,例如:watch
可以进行异步操作
- 两个重要的小原则:
- 所被Vue管理的函数,最好写成普通函数,这样
this
的指向才是vm
或组件实例
对象 - 所有不被Vue所管理的函数(定时器的回调函数、
ajax
的回调函数等、Promise
的回调函数),最好写成箭头函数,这样this
的指向才是vm
或组件实例
对象
- 所被Vue管理的函数,最好写成普通函数,这样
绑定样式
-
class样式
写法
:class="xxx"
xxx可以是字符串、对象、数组- 字符串写法适用于:类名不确定,要动态获取
- 数组写法适用于:要绑定多个样式,个数不确定,类名不确定
- 对象写法适用于:要绑定多个样式,个数确定(属性个数),类名称确定(属性名称),但不确定用不用(属性值true,false)
-
style样式
:style="{fontSize: xxx}"
其中xxx是动态值。:style="[a,b]"
其中a、b是样式对象。
示例:
css
.basic{
width: 400px;
height: 100px;
border: 1px solid black;
}
.happy{
border: 4px solid red;;
background-color: rgba(255, 255, 0, 0.644);
background: linear-gradient(30deg,yellow,pink,orange,yellow);
}
.sad{
border: 4px dashed rgb(2, 197, 2);
background-color: gray;
}
.normal{
background-color: skyblue;
}
.test1{
background-color: yellowgreen;
}
.test2{
font-size: 30px;
text-shadow:2px 2px 10px red;
}
.test3{
border-radius: 20px;
}
html结构
<div id="root">
<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
<div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br/><br/>
<!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、样式的类名不确定 -->
<div class="basic" :class="classArr">{{name}}</div> <br/><br/>
<!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、样式的类名也确定,但要动态决定用不用 -->
<div class="basic" :class="classObj">{{name}}</div> <br/><br/>
<!-- 绑定style样式--对象写法 -->
<div class="basic" :style="styleObj">{{name}}</div> <br/><br/>
<!-- 绑定style样式--数组写法 -->
<div class="basic" :style="styleArr">{{name}}</div>
</div>
vm实例
const vm = new Vue({
el: '#root',
data: {
name: '样式渲染',
mood: 'normal',
classArr: ['test1', 'test2', 'test3'],
classObj: {
test1: false,
test2: false,
},
styleObj: {
fontSize: '40px',
color: 'red',
},
styleObj2: {
backgroundColor: 'orange'
},
styleArr: [
{
fontSize: '40px',
color: 'blue',
},
{
backgroundColor: 'gray'
}
]
},
methods: {
changeMood() {
const arr = ['happy', 'sad', 'normal']
const index = Math.floor(Math.random() * 3)
this.mood = arr[index]
}
},
})
条件渲染
-
v-if
-
写法
<div v-if="n === 1">Angular</div> <div v-else-if="n === 2">React</div> <div v-else-if="n === 3">Vue</div> <div v-else>哈哈</div>
-
适用于:切换频率较低的场景
-
特点:不展示的DOM元素直接被移除
-
注意:
v-if
可以和v-else-if
、v-else
一起使用,但要求结构不能被"打断"
-
-
v-show
-
写法:
v-show="表达式"
<h2 v-show="false">欢迎来到{{name}}</h2> <h2 v-show="1 === 1">欢迎来到{{name}}</h2>
-
适用于:切换频率较高的场景
-
特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉
-
-
备注:使用
v-if
的时,元素可能无法获取到,而使用v-show
一定可以获取到
v-for指令
- 用于展示列表数据
- 语法:
v-for="(item, index) in xxx" :key="yyy"
- 可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
<!-- 遍历数组 -->
<h2>人员列表(遍历数组)</h2>
<ul>
<li v-for="(p,index) of persons" :key="index">
{{p.name}}-{{p.age}}
</li>
</ul>
<!-- 遍历对象 -->
<h2>汽车信息(遍历对象)</h2>
<ul>
<li v-for="(value, k) of car" :key="k">
{{k}}-{{value}}
</li>
</ul>
<!-- 遍历字符串 -->
<h2>测试遍历字符串(用得少)</h2>
<ul>
<li v-for="(char, index) of str" :key="index">
{{char}}-{{index}}
</li>
</ul>
<!-- 遍历指定次数 -->
<h2>测试遍历指定次数(用得少)</h2>
<ul>
<li v-for="(number, index) of 5" :key="index">
{{index}}-{{number}}
</li>
</ul>
key的内部原理
react、vue中的key有什么作用?(key的内部原理)
-
虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】
随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较 -
对比规则:
- 旧虚拟DOM中找到了与新虚拟DOM相同的key
- 若虚拟DOM中内容没变,直接使用之前的真实DOM
- 若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
- 旧虚拟DOM中未找到与新虚拟DOM相同的key
- 创建新的真实DOM,随后渲染到到页面
-
用index作为key可能会引发的问题:
- 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
- 会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低
- 如果结构中还包含输入类的DOM:
- 会产生错误DOM更新 ==> 界面有问题
- 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
-
开发中如何选择key:
最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值
如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示, 使用
index
作为key
是没有问题的
Vue监视数据的原理
-
vue会监视data中所有层次的数据
-
如何监测对象中的数据
通过
setter
实现监视,且要在new Vue
时就传入要监测的数据- 对象中后追加的属性,
Vue
默认不做响应式处理 - 如需给后添加的属性做响应式,请使用如下API
Vue.set(target, propertyName/arrayIndex, value)
vm.$set(target, propertyName/index, value)
- 对象中后追加的属性,
-
如何监测数组中的数据
通过包裹数组更新元素的方法实现,本质就是做了两件事
- 调用原生对应的方法对数组进行更新
- 重新解析模板,进而更新页面
-
在Vue修改数组中的某个元素一定要用如下方法
- 使用这些API:
push()
、pop()
、shift()
、unshift()
、splice()
、sort()
、reverse()
Vue.set()
或vm.$set()
- 使用这些API:
-
特别注意:
Vue.set()
和vm.$set()
不能给vm或vm的根数据对象添加属性
模拟数据监测代码
let data = {
name: '我是vue',
address: '北京',
}
// 创建一个监视的实例对象,用于监视data中属性的变化
const obs = new Observer(data)
console.log(obs)
//准备一个vm实例对象
let vm = {}
vm._data = data = obs
function Observer(obj) {
//汇总对象中所有的属性形成一个数组
const keys = Object.keys(obj)
//遍历
keys.forEach((k) => {
Object.defineProperty(this, k, {
get() {
return obj[k]
},
set(val) {
console.log(`${k}被改了,我要去解析模板,生成虚拟DOM.....我要开始忙了`)
obj[k] = val
}
})
})
}
收集表单数据
- 若:
<input type="text"/>
,则v-model
收集的是value
值,用户输入的就是value
值。 - 若:
<input type="radio"/>
,则v-model
收集的是value
值,且要给标签配置value
值。 - 若:
<input type="checkbox"/>
- 没有配置
input
的value
属性,那么收集的就是checked
(勾选or未勾选,是布尔值) - 配置
input
的value
属性:v-model
的初始值是非数组,那么收集的就是checked
(勾选or未勾选,是布尔值)v-model
的初始值是数组,那么收集的的就是value
组成的数组
- 没有配置
- 备注:
v-model
的三个修饰符:lazy
:失去焦点再收集数据number
:输入字符串转为有效的数字trim
:输入首尾空格过滤
过滤器
-
定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)
-
语法
- 注册过滤器:
Vue.filter(name, callback)
或new Vue{filters:{}}
- 使用过滤器:
{{ xxx | 过滤器1 | 过滤器2}}
或v-bind:属性 = "xxx | 过滤器名"
- 注册过滤器:
-
备注
过滤器也可以接收额外参数、多个过滤器也可以串联
并没有改变原本的数据, 是产生新的对应的数据
示例
//全局过滤器
Vue.filter('mySlice', function (value) {
return value.slice(0, 4)
})
new Vue({
el: '#root',
data: {
time: 1621561377603, //时间戳
msg: '你好,同学'
},
//局部过滤器
filters: {
timeFormater(value, str = 'YYYY年MM月DD日 HH:mm:ss') {
// console.log('@',value)
return dayjs(value).format(str)
}
}
})
html模版
<div id="root">
<h2>显示格式化后的时间</h2>
<!-- 过滤器实现 -->
<h3>现在是:{{time | timeFormater}}</h3>
<!-- 过滤器实现(传参) -->
<h3>现在是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3>
<h3 :x="msg | mySlice">你好,vue</h3>
</div>
内置指令
-
v-bind: 单向绑定解析表达式, 可简写为 :xxx
-
v-model: 双向数据绑定
-
v-for: 遍历数组/对象/字符串
-
v-on: 绑定事件监听, 可简写为@
-
v-if: 条件渲染(动态控制节点是否存存在)
-
v-else: 条件渲染(动态控制节点是否存存在)
-
v-show: 条件渲染 (动态控制节点是否展示)
-
v-text: 向其所在的节点中渲染文本内容,
v-text
会替换掉节点中的内容,{{xx}}
则不会 -
v-html: 向指定节点中渲染包含
html
结构的内容,v-html
会替换掉节点中所有的内容,{{xx}}
则不会,v-html
可以识别html
结构(有安全性问题,xss攻击) -
v-cloak: 使用
css
配合v-cloak
可以解决网速慢时页面展示出{{xxx}}
的问题:<h2 v-cloak>{{name}}</h2>
[v-cloak] { display:none; } /* 加载Vue,如果网络慢就将页面隐藏掉,不会显示{{xxx}}的问题 */
-
v-once: 所在节点在初次动态渲染后,就视为静态内容了,以后数据的改变不会引起
v-once
所在结构的更新,可以用于优化性能 -
v-pre: 跳过其所在节点的编译过程(不会去编译这个节点),可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译
自定义指令
-
定义语法
- 局部指令:
new Vue({directives:{指令名:配置对象} 或 directives:{指令名:回调函数} })
- 全局指令:
Vue.directive(指令名, 配置对象) 或 Vue.directive(指令名, 回调函数)
- 局部指令:
-
配置对象中常用的3个回调
bind:指令与元素成功绑定时调用
inserted:指令所在元素被插入页面时调用
update:指令所在模板结构被重新解析时调用
在回调方法中都有2个参数element-DOM元素,binding-绑定的值 -
备注
指令定义时不加v-,但使用时要加v-
指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名
directives:{
'big-number'(element, binding){
// console.log('big')
element.innerText = binding.value * 10
},
// big函数何时会被调用?
// 1.指令与元素成功绑定时(一上来)
// 2.指令所在的模板被重新解析时
// html元素可以这么写 <span v-big="n">
big(element, binding){
console.log('big',this) //注意此处的this是window
// console.log('big')
element.innerText = binding.value * 10
},
// html元素 <input type="text" v-fbind:value="n">
fbind:{
//指令与元素成功绑定时(一上来)
bind(element, binding){
element.value = binding.value
},
//指令所在元素被插入页面时
inserted(element, binding){
element.focus()
},
//指令所在的模板被重新解析时
update(element, binding){
element.value = binding.value
}
}
}
生命周期
- 又名:生命周期回调函数、生命周期函数、生命周期钩子
- 是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数
- 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的
- 生命周期函数中的
this
指向是vm或组件实例对象
常用的生命周期钩子:
- mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
- beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。
关于销毁Vue实例
- 销毁后借助Vue开发者工具看不到任何信息。
- 销毁后自定义事件会失效,但原生DOM事件依然有效。
- 一般不会在
beforeDestroy
操作数据,因为即便操作数据,也不会再触发更新流程了。
Vue组件
- Vue中使用组件的三大步骤
- 定义组件(创建组件)
- 注册组件
- 使用组件(写组件标签)
-
如何定义一个组件
- 使用
Vue.extend(options)
创建,其中options
和new Vue(options)
时传入的那个options
几乎一样,但也有点区别:- el不要写,为什么? --- 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器
- data必须写成函数,为什么? --- 避免组件被复用时,数据存在引用关系
备注:使用template可以配置组件结构
- 使用
-
如何注册组件
- 局部注册:靠
new Vue
的时候传入components
选项 - 全局注册:靠
Vue.component('组件名', 组件)
- 局部注册:靠
-
编写组件标签,比如:
<school></school>
关于组件名
-
一个单词组成
第一种写法(首字母小写):
school
第二种写法(首字母大写):School
-
多个单词组成
第一种写法(kebab-case命名):
my-school
第二种写法(CamelCase命名):MySchool
(需要Vue
脚手架支持) -
注意
组件名尽可能回避
HTML
中已有的元素名称,例如:h2
、H2
都不行
可以使用name
配置项指定组件在开发者工具中呈现的名字
关于组件标签
第一种写法:
<school></school>
第二种写法:<school/>
注意:不用使用脚手架时,<school/>
会导致后续组件不能渲染
简写方式
const school = Vue.extend(options)
可简写为:const school = options
其实当我们没有写
Vue.extend
时Vue框架会给我们自动加上Vue.extend
来给生成组件,后期在写组件时可以省略Vue.extend
关于VueComponent
school
组件本质是一个名为VueComponent
的构造函数,且不是程序员定义的,是Vue.extend
生成的- 我们只需要写
<school/>
或<school></school>
,Vue
解析时会帮我们创建school
组件的实例对象,即Vue
帮我们执行的:new VueComponent(options)
- 特别注意:每次调用
Vue.extend
,返回的都是一个全新的VueComponent
!!!! - 关于this指向:
- 组件配置中:
data
函数、methods
中的函数、watch
中的函数、computed
中的函数 它们的this
均是【VueComponent
实例对象】 new Vue(options)
配置中:data
函数、methods
中的函数、watch
中的函数、computed
中的函数 它们的this
均是【Vue
实例对象】
- 组件配置中:
VueComponent
的实例对象,以后简称vc
(也可称之为:组件实例对象)。Vue
的实例对象,以后简称vm
- 一个重要的内置关系:
VueComponent.prototype.__proto__ === Vue.prototype
- 为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法
到此Vue基础部分到此,后期我们就可以学习单文件组件了,写单文件组件需要vue脚手架中项目中写
标签:vue,DOM,vm,value,Vue,基础教程,组件,data From: https://www.cnblogs.com/wdszh/p/17521766.html