我们已经涵盖了大部分的基础知识,现在,是时候深入底层原理了!
Vue最显著的特性之一便是不太引人注意的响应式系统。模型层(model)只是普通的js对象,修改它则更新视图(view),这会让状态管理变得非常简单且直观
(一)如何追踪变化?
把一个普通的JS对象传给Vue实例的data选项,Vue将会遍历此对象的所有属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。Object.defineProperty 是仅 ES5 支持,且无法 shim 的特性,这也就是为什么 Vue 不支持 IE8 以及更低版本浏览器的原因。
每个组件实例都有相应的watcher实例对象,他会在组件渲染的过程中把属性记录为依赖,之后当依赖的setter被调用时,会通知watcher重新计算,从而使它关联的组件得以更新
(二)变化检测问题
受现代 JavaScript 的限制(以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的
比如:
var vm = new Vue({
data: {
a: 1
}
})
// vm.a是相应的
vm.b = 2 // vm.b是非相应的
解决方法:
1.Vue.set(vm.arr,1,'ddd')
2.vm.$set(vm.arr,1,'ddd')
(三)声明响应式属性
由于Vue不允许动态添加根级响应式属性,所以你必须在初始化实例前声明根级响应式属性,哪怕只是一个空值
var vm = new Vue({
el: '#app',
data: {
a: 1,
b: ''
}
})
这样的限制在背后是有其技术原因的,它消除了在依赖项跟踪系统中的一类边界情况,也使 Vue 实例在类型检查系统的帮助下运行的更高效。而且在代码可维护性方面也有一点重要的考虑:data 对象就像组件状态的概要,提前声明所有的响应式属性,可以让组件代码在以后重新阅读或其他开发人员阅读时更易于被理解。
(四)异步更新队列
为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用 Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用
比如:
<div id="app">
<p>{{ a }}</p>
</div>
var vm = new Vue({
el: '#app',
data: {
a: 1
}
})
vm.a=10;
alert(vm.$el.textContent);
vm.$nextTick(function(){
alert(vm.$el.textContent)
})