vue数据双向绑定的原理:采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
以上属于官方说法,听得似懂非懂,只知道vue的双向绑定采用了js中的Object.defineProperty方法,其中get方法是值读取时触发函数,set是设置值时触发函数,当监听到数据变化时把变化的消息通知订阅者,触发相应的监听回调。
但是发布者订阅者是谁?相应的监听回调又是什么?
我查了很多资料,这个vue的双向绑定原理及实现 - canfoo#! - 博客园是最详细的,还有代码进行参考。以下我就来班门弄斧以下,具体实现可以看链接里面的内容。
实现数据的双向绑定简单的分为三步:
1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者
2.实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图
3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。
注意事项:
1.由于javaScript的限制,vue不能监听数组和对象的变化
关于对象:Vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data
对象上存在才能让 Vue 将它转换为响应式的
使用Vue.set(vm.someObject, 'b', 2)或者this.$set(this.someObject,'b',2)解决
关于数组:Vue 不能检测以下数组的变动:
- 当你利用索引直接设置一个数组项时,例如:
vm.items[indexOfItem] = newValue
- 当你修改数组的长度时,例如:
vm.items.length = newLength
解决方式Vue.set(vm.items, indexOfItem, newValue),vm.$set(vm.items, indexOfItem, newValue)或者vm.items.splice(indexOfItem, 1, newValue),vm.items.splice(newLength)
2.vue的更新是异步的。
Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新,简单来说,Vue 在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。
以下需要使用nextTick常见情况:
就情况二举个例子:
1、点击按钮显示原本以 v-show = false 隐藏起来的输入框,并获取焦点。
showsou(){
this.showit = true //修改 v-show
document.getElementById("keywords").focus() //在第一个 tick 里,获取不到输入框,自然也获取不到焦点
}
修改为:
showsou(){
this.showit = true
this.$nextTick(function () {
// DOM 更新了
document.getElementById("keywords").focus()
})
}