详解详解Vue源码学习之双向绑定源码学习之双向绑定
主要介绍了Vue源码学习之双向绑定,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参
考学习价值,需要的朋友们下面随着小编来一起学习学习吧
原理
当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty
把这些属性全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是为什么 Vue 不支持 IE8
以及更低版本浏览器。
上面那段话是Vue官方文档中截取的,可以看到是使用Object.defineProperty实现对数据改变的监听。Vue主要使用了观察者
模式来实现数据与视图的双向绑定。
function initData(vm) { //将data上数据复制到_data并遍历所有属性添加代理
vm._data = vm.$options.data;
const keys = Object.keys(vm._data);
let i = keys.length;
while(i--) {
const key = keys[i];
proxy(vm, `_data`, key);
}
observe(data, true /* asRootData */) //对data进行监听
}
在第一篇数据初始化中,执行new Vue()操作后会执行initData()去初始化用户传入的data,最后一步操作就是为data添加响应
式。
实现
在Vue内部存在三个对象:Observer、Dep、Watcher,这也是实现响应式的核心。
Observer
Observer对象将data中所有的属性转为getter/setter形式,以下是简化版代码,详细代码请看这里。
export function observe (value) {
//递归子属性时的判断
if (!isObject(value) || value instanceof VNode) {
return
}
...
ob = new Observer(value)
}
export class Observer {
constructor (value) {
... //此处省略对数组的处理
this.walk(value)
}
walk (obj: Object) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i]) //为每个属性创建setter/getter
}
}
...
}
//设置set/get
export function defineReactive (
obj: Object,
key: string,
val: any
) {
//利用闭包存储每个属性关联的watcher队列,当setter触发时依然能访问到
const dep = new Dep()
...
//如果属性为对象也创建相应observer
let childOb = observe(val)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
if (Dep.target) {
dep.depend() //将当前dep传到对应watcher中再执行watcher.addDep将watcher添加到当前dep.subs中