v-model双向绑定原理_Vue数据绑定

这是一篇简单的学习笔记。在学习一段时间Vue后,尝试实现一下Vue的数据绑定。

相关源码:https://github.com/buchuitoudegou/Data-Binding-demo

bab8927a0a446605b5d53d9c76dd508a.png

Vue的数据绑定机制利用了观察者设计模式,利用侦听器动态更新DOM元素中的值,以下是Vue在编译时绑定数据的过程。

绑定setter和getter

index.mjs是编译的入口。从SelfVue的构造函数我们可以看到,对于options中的data,我们会先对它进行一个observe的操作,即绑定getter和setter,这也是数据响应模式构造的开始。

// index.mjs

defineReactive函数递归给data对象的每个属性(如果该属性也是对象,则递归执行)绑定getter和setter。

getter是这样定义的:如果这个属性被订阅了,则将它的侦听器加入到订阅数组中,最后返回这个属性的值。

// Dep.mjs

这里提到了两个概念侦听器(Watcher)和订阅(Dep)数组。侦听器接下来会提到,先简单介绍一下订阅的概念。订阅器(Dep)是一个实例,每个data中的对象(Object)都会有一个Dep实例(data自己也会有一个),它里面定义了订阅数组,存储了所有订阅某个属性的侦听器。订阅器有一个notify方法,用于通知订阅数组里面所有的侦听器,某个值发生了改变(并不会判断该侦听器是否侦听了这个值)。另外,订阅器类(Dep)有一个静态属性target,用于存储当前正在进行订阅操作的属性(相当于订阅器的办事窗口,而且只有一个窗口)。

介绍完订阅器的概念之后,继续之前的内容,setter的定义应该就可以猜到了:setter在调用时,除了更新这个属性的值,还会调用订阅器的notify。

上面的步骤是Vue的root实例在定义的时候做的第一步工作。由于这个时候还不知道哪些属性会绑定到DOM上,因此,所有订阅器的订阅数组都是空的。

编译DOM节点

// Compile.mjs

这个步骤里,我们会知道哪些节点(HTMLElement或者文本节点)会和Vue的data有互动。给这些有互动的节点设置侦听器(Watcher)。接下来介绍一下Watcher。

Watcher设置

// Watcher.mjs

侦听器,顾名思义用于侦听某个属性的值是否发生了变化。我们在给某个属性构造侦听器的时候需要传入一个回调函数,这个回调函数用于更新对应DOM节点的值。至于哪个节点对应哪个属性值我们在编译的时候就可以得知。

Watcher在构造的时候,会强行调用这个属性值的getter。这是为什么呢?之前我们也提到过,getter中定义了,若某个值被订阅,则它的侦听器会加入到订阅数组中。因此,给某个值构造Watcher时,先让Dep的订阅窗口(Dep.target)指向这个Watcher,说明这个值需要被订阅,然后再调用这个值的getter,这样子Dep的订阅数组中就会把这个Watcher放进去。最后将订阅窗口(Dep.target)指向null,表示订阅完成,可以订阅下一个属性。

每个Watcher都会有一个update方法,用于调用之前提到过的回调函数。当Dep调用notify方法的时候,就会触发每个在订阅数组中的Watcher的update方法。update方法中确认自己的侦听的值是否发生了变化,若发生了变化则调用构造的时候传入的回调函数,更新DOM元素中的值。

当一个值发生变化时

当data中一个值发生了变化时,setter会调用对应Dep实例的notify函数,notify函数调用实例中存储的订阅数组中所有侦听器的update方法。update方法中,侦听器会判断自己侦听的值是否发生了变化。若发生了变化,则调用回调函数,更新DOM节点中的值。

参考

双向绑定

vue 的双向绑定原理及实现 - 前端 - 掘金

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值