vue双向绑定原理的思考

2018-05-30  本文已影响0人  victoriasuli

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)

上一篇下一篇

猜你喜欢

热点阅读