深入响应式原理
2019年5月27号的这天我们学习了vue中的深入响应式原理
官方文档:
https://cn.vuejs.org/v2/guide/reactivity.html
如果追踪变化
当你把一个普通的javaScript对象传入Vue实例作为data选项,Vue 将遍历此对象所有的属性,幷使用object.defineProerty 把这些属性全部转换为getter/setter。Object.defineProerty是ES5中一个无法shim的特性,这也就是vue 不支持ie8以及更低版本游览器的原因。
这些getter/settr对用户来说是不可见的,但是在内部他们让vue能够追踪依赖,在属性被访问和修改时通知变更。这里需要注意的是不同的游览器在控制台打印数据对象时对gettr/setter的格式化幷不同,所以建议安装vue-devtools来获取对检查数据更加友好的用户界面。
每一个组件实例都对应一个watcher实例,他会在组件渲染的过程中吧“接触”过的数据属性记录为依赖。之后当依赖项的setter触发时,会通知watcher,从而使他们关联的组件重新渲染。
检测变化的注意事项
受现代javascript的限制(
Object.observe
也已经被废除),vue 无法检测到对象属性的添加或删除。 由于vue会把初始化实例时对属性执行getter/setter转化,所以属性必须在 data 对象上存在才能让vue 将它转化成为响应式的。由于vue 会在初始化实例时对属性执行getter/setter转换,所以属性必须在data对象上存在才能让vue将它转化为响应式的。例如:
var vm = new Vue({
data:{
a : 1
}
})
// `vm.a`是响应式
vm.b=2
// vm.b 是非响应式的
对于已经创建的实例,vue 不允许动态添加根级别的响应式属性。但是,可以使用Vue.set(object , peopertName ,value)方法向嵌套对象添加响应式属性。例如,对于:
vue.set(vm.someObject,' b ' ,2
你还可以使用vm.$set
实例方法,这也是全局Vue.set
方法的别名:
this.$sets (this.someObject,'b',2)
有时候你可能为有对象赋值多个新属性,比如使用object.assign()或· _.extend( )
.但是,这样添加到对象上的新属性不会触发更新。在这种情况下,你应该用原对象与要混合进行的对象的属性一起创建一个新的对象。
// 替代 ‘Object.assign(this.someObject,{a: 1 , b : 2})’
也有一些数组相关的注意事项,之前已经在列表渲染中讲过
声明响应式属性
由于vue 不允许动态加根级响应式属性,所以你必须在初始化实例前声明所有根级响应式属性,哪怕只是一个空值:
var vm= new Vue({
data : {
///声明 message 为一个空值字符串
message :“ ”
}
template :‘ <div>{{
message}}</div>’
})
vm.message = ' Hello'
如果你还未 data 选项中说明 message ,vue ,并且回调函数中的 this将自动绑定到当前的vue 实例上:
Vue.component('example', {
template: '<span>{{ message }}</span>',
data: function () {
return {
message: '未更新'
}
},
methods: {
updateMessage: function () {
this.message = '已更新'
console.log(this.$el.textContent) // => '未更新'
this.$nextTick(function () {
console.log(this.$el.textContent) // => '已更新'
})
}
}
})
因为 $nextTick() 返回一个 Promise 对象,所以你可以使用新的 ES2016 async/await 语法完成相同的事情:
methods: {
updateMessage: async function () {
this.message = '已更新'
console.log(this.$el.textContent) // => '未更新'
await this.$nextTick()
console.log(this.$el.textContent) // => '已更新'
}
}