vue双向绑定原理的思考
1.初始化时data的值如何渲染进DOM?
2.元素节点改变了值,怎样通知data里的值改变?
3.data里的值改变,怎么通知文本节点中的属性值改变?
1.初始化时data的值如何渲染进DOM?
遍历所有DOM节点,如果有绑定data中的值的节点,把值赋给节点
需要一个仓库,createDocumentFragment(),里面放所有节点,把值替换完成后,再将这个仓库整体插入到DOM中,此番操作能减少操作DOM的开销。
创建仓库compile函数,是判断节点的类型并赋值的一个函数。节点按类型分为元素节点和文本节点:
如果是文本节点,直接用正则表达式取两个大括号里的值作为data的key,再将data[key]赋给这个属性。
如果是元素节点,首先遍历节点上的所有属性,如果有属性是‘v-model’,则取v-model绑定的属性作为data的key值,再将data[key]赋给这个属性。
判断节点并赋值 vue实例2.元素节点改变了值,怎样通知data里的值改变?
对于元素节点,在之前的compile函数中,给带有v-model的节点加监听,一旦值发生改变,则将变化值赋给data中对应的值。
3.data里的值改变,怎么通知文本节点中的属性值改变?
需要在data变化之后做点儿什么,先对data里的所有属性来个劫持,利用defineProperty劫持他们的get,set方法
vue实例化时 属性劫持我们应该在set的时候,将newVal通知给文本元素进行更新,但是问题是,哪一个节点应该对应哪一个属性?
我们可以在每个data的属性上绑定一个容器(依赖),在一开始初始化时,拿data中的值时,会调用get方法。我们在get里,只要一调用,就把这个节点push进依赖,等到set的时候,遍历这个依赖里的节点,进行赋值。
这个依赖应该具备两个方法,一个是添加,一个是通知。
addsubs方法将所有节点记录下来,push进数组;notify通知文本节点完成值的替换。
依赖原型链上的方法 属性劫持时干的活儿至于,啥时候开始push节点呢?得等建立连接之后,也就是判断有没有v-model,如果有就取data中的值,赋给节点的值,在这之后push。
除了push节点,我们还需要更新的函数,我们在这里封装一个容器,其中包含了节点,以及自身的更新函数。这个容器就是订阅者,watcher。watcher:
1.watcher构造方法里首先把Dep设为有值的,然后执行update方法。
2.在update方法中,首先去取data中的值,这就触发了属性劫持的get方法,并且现在全局标志Dep不为空。这个时候,在属性劫持的get方法中,依赖dep就把订阅者watcher push进去了。
然后取到值,给节点赋值(我觉得这里就是初始化的赋值)。
3.之后完成初始化的赋值,把全局标志置为null,作用是:等下次调用更新方法时,还会触发属性劫持的get方法,到这时候不会再往dep里push了。
总结:
1.两类DOM节点,带{{}}的文本节点,和带v-model的元素节点,这两类节点以及自身的更新方法被封装成watcher,即订阅者。
2.每个data中双向绑定的属性,每个属性上都有依赖Dep,依赖里带有通知和添加两个方法。即发布者。
3.Object.defineProperty
set:dep.notify
get : dep.addSubs();
this.subs.push(watcher)