Vue中 options 和 instance 的理解
var vm = new Vue(options)
在Vue实例化的过程中,传入的值称为 options, 生成的对象 vm 称为 instance,在Vue的官网上有 options 与 instance 的介绍,点击跳转,Vue实例代理了对 options 对象的访问,比如:
- vm.$data 代理了对 options 中 data 属性的访问
- vm.$props 代理了对 options 中 props 属性的访问
Vue中 $ 开头的属性和 _(下划线)开头的属性
Vue中有很多以 $ 开头和以 _ (下划线)的属性,其中以 $ 开头的属性让开发者使用,以_下划线开头的为内置属性,不建议开发者使用
- vm.$ 等价于 vm
- vm.$data.name 等价于 vm.name
let vm = new Vue({
el: "#app",
data:{ name: 'XiongHe' },
})
vm.$data.name
vm.name
vm._data.name
// XiongHe 读取实例属性 vm.name
// XiongHe 读取 data 数据 vm._data.name
// XiongHe
Vue选项options
var vm = new Vue({
// 数据
data: "Vue实例的数据对象",
props: "用于接收来自父组件的数据,props 可以是数组或对象",
propsData: "创建实例时传递 props,主要作用是方便测试",
computed: "计算属性,结果会被缓存",
methods: "方法,可以通过 VM 实例访问",
watch: "一个对象,键是需要观察的表达式,值是对应回调函数,Vue 实例将会在实例化时"
"调用$watch(),遍历 watch 对象的每一个 property"
// DOM
el: "提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标",
template: "可以替换挂载元素的字符串模板",
render: "渲染函数,字符串模板的替代方案",
renderError: "仅用于开发环境,在render()出现错误时,提供另外的渲染输出"
// 生命周期钩子
beforeCreate: "发生在Vue实例初始化之后,data、observer、event/watcher事件被配置之前执行",
created: "发生在Vue实例初始化以及data、observer、event/watcher事件被配置之后",
beforeMount: "在挂载开始之前被调用:相关的 render 函数首次被调用",
mounted: "实例被挂载后调用,这时 el 被新创建的 vm.$el 替换了",
beforeUpdate: "在数据发生改变后,DOM 被更新之前被调用",
updated: "在数据更改导致的虚拟 DOM 重新渲染和更新完毕之后被调用",
activated: "被 keep-alive 缓存的组件激活时调用",
deactivated: "被 keep-alive 缓存的组件失活时调用",
beforeDestory: "实例销毁之前调用。在这一步,实例仍然完全可用",
destoryed: "实例销毁后调用"
errorCaptured: "在捕获一个来自后代组件的错误时被调用"
// 资源
components: "包含 Vue 实例可用组件的哈希表"
directives: "包含 Vue 实例可用指令的哈希表",
filters: "包含 Vue 实例可用过滤器的哈希表"
// 组合
mixins: "将属性混入Vue实例对象,并在Vue自身实例对象的属性被调用之前得到执行",
parent: "指定已创建的实例之父实例,在两者之间建立父子关系"
"子实例可以用 this.$parent 访问父实例,"
"子实例被推入父实例的 $children 数组中"
extends: "允许声明扩展另一个组件",
provide/inject: "这对选项需要一起使用,用来向所有子组件注入依赖"
// 其他
}})
Vue实例 Instance
Vue 实例自带的原生属性与方法,带前缀 $,以便与用户定义的属性区分开来,以下介绍几个源码中常见的属性:
Vue Instance 属性
1、vm.$el
vm 挂载的 DOM 节点,写法有三种:
el: '#app'
el: 'div'
el: document.getElementById('app')
// el 实例的value值和HTML模板建立关联,实现事件、属性和HTML模板的绑定
<div id="app"></div>
2、vm.$options
<div id="app">
<button @click="myClick()"></button>
</div>
let vm = new Vue({
el: "#app",
customOption: 'foo',
methods: {
myClick() { console.log(vm.$options) },
myClick2() { console.log('this is myClick2') }
}
})
Vue 实例的创建通过 new Vue(options) 来实现,options 是创建 Vue 实例传递的参数,它是一个对象,包含 Vue 实例的所有属性(包含原生属性)和方法(包含原生方法),console.log(vm.$options)打印结果如下:
3、vm.children、vm.$root
<根组件>
<子组件>
<孙组件>
.....
<孙组件>
<子组件>
<根组件>
根实例的访问:$root
父组件的访问:$parent $parent.$parent
子组件的访问:$children
4、vm.$Props
当前组件接收到的 props 对象,Vue 实例代理了对其 props 对象 property 的访问
5、vm.$data
Vue 实例观察的数据对象,Vue 实例代理了对其 data 对象 property 的访问
6、vm.$slot
当前组件接受的 props 对象
7、vm.$refs
注册过 ref 的 DOM 元素或者组件实例
Vue Instance 方法
1、vm.$watch
vm.$watch 功能上和 Vue 实例上的 watch 方法相同
<div id="app"> {{ count }} </div>
const vm = new Vue({
el: "#app",
data: { count: 0 },
watch: {
count(newValue,oldValue){
console.log(`${oldValue} : ${newValue}`);
}
},
})
setInterval(() => {
vm.$data.count += 1;
}, 1000)
//count : 监听的属性值
//newValue: 变化之后count的值
//oldValue: 变化之前count的值
vm.$watch('count', (newValue,oldValue) => {
console.log(`${oldValue} : ${newValue}`);
})
//上述vm.$watch实现方法和 vm实例中watch中实现的功能相同
不同点:
vm 中 watch 方法中对 count 的监听在 vm 实例销毁的时候自动移除。
通过 vm.$watch 添加的监听,需要主动移除监听。
2、vm.$set
vm.$set 是给响应式的对象(基本都是 Vue 实例中的 data 对象)添加一个新的属性,并且这个新的属性也是响应式的
//obj是响应式对象,obj.count每次改变,都会重新渲染
const vm = new Vue({
el: "#app",
template: `<div>{{ obj.count }}</div>`,
data: { obj:{ count: 0 } }
})
let num = 1;
setInterval(() => {
num++;
vm.$set(vm.obj, 'count', num);
}, 1000)
3、vm.$delete
删除对象属性。响应式对象删除的时候会更新视图
4、vm.on、vm.$off
vm.$emit 触发一个自定义事件
vm.$on 监听当前实例上的自定义事件
vm.$off 移除自定义事件监听器
vm.$on('test', function (msg) {
console.log(msg)
})
vm.$emit('test', 'hi')
Vue Instance 生命周期
1、vm.$mount
手动地挂载一个未挂载的实例到元素上
new Vue({
data: {
msg: 'hello vue'
}
}).$mount('#app')
2、vm.$forceUpdate
迫使 Vue 实例重新渲染
3、vm.$nextTick
将回调延迟到下次 DOM 更新循环之后执行
4、vm.destory
完全销毁一个实例
Vue实例和Vue的实例
Vue 实例包括 Vue 实例和 Vue 的实例(Vue 组件实例)
Vue实例
在 Vue 的项目中,只有一个 Vue 实例在 main.js 文件中定义
new Vue({
el:'#app',
data:{
msg:'hello world'
}
})
Vue的实例
Vue 是由一个个实例构建而成,每一个 Vue 的组件都是 Vue 的实例,任何一个 Vue 项目都是由很多个 Vue 实例组成,上文提到的vm.$parent、vm.$children、vm.$root,都是Vue 的实例
Vue中的数据代理
定义: 通过vm对象来代理 data 对象中属性的操作(读/写)
优势: 更加方便的操作 data 中的数据
原理:
- 通过
Object.defineProperty()把 data 对象中所有属性添加到 vm 上 - 为每一个添加到 vm 上的属性,都指定一个
getter/setter - 在
getter/setter内部去操作(读/写)data 中对应的属性
Object.defineProperty(object, propertyname, descriptor)
object:必须,要在其上添加或修改属性的对象propertyname:必需。 一个包含属性名称的字符串descriptor:属性描述符。 它可以针对数据属性或访问器属性
descriptor:有以下参数值
value:该属性的值,默认为 undefinedwritable:该属性是否可写,默认为 falseconfigurable:控制了该属性是否可被改变、是否可删除,默认为 falseenumerable:该属性是否可枚举,默认为 falseget:给属性提供 getter 的方法,若是没有 getter 则为 undefinedset:给属性提供 setter 的方法,若是没有 setter 则为 undefined
let obj = { x: 100 }
let obj2 = { y: 200 }
Object.defineProperty(obj2, 'z', {
get() { return obj.x },
set(value) { obj.x = value + 1001 },
})
obj2.z = 100
obj
// { x: 1101 }
以上是一个简单的数据代理实现,通过 obj2 可以对 obj1 的属性值进行操作
let vm = new Vue({
el: "#app",
customOption: 'foo',
data:{
name: 'XiongHe',
gender: '男',
msg: '程序员'
},
methods: {
myClick() {
console.log(vm)
},
myClick2() {
console.log('')
}
}
})
在控制台打印 vm.$data 对象,可以看到 data 对象中的属性都做了代理,也就是通过getter/setter方式访问,通过Object.defineProperty()方法为每个属性添加了getter/setter方法,在读取 data 中的属性时,也是通过getter/setter方法访问_data,通过 _data 对象操作 data 对象
在 vm 实例中,不仅 data 对象被代理到 vm 实例,还有很多其他对象也被代理到 vm 实例上,如下图: