花了两天时间,跟着b站博主手敲了一遍vue的双向绑定原理。写个博客复盘一下。
在写博客之前,先说一句:尤雨溪牛逼!
一、首先写一个html界面,并引入我们自己实现的vue.js文件
Document
阿婆主:{{name}}
更多:{{more.like}}
你好
二、实现vue.js文件。
vue的双向绑定原理是通过数据劫持,结合发布订阅者模式实现的。
(1)首先要实现对数据的监听,因此实现Observer类,在该类中使用Object.defineProperty(obj,key,{enumerable:true, configurable:true,get(){},set(){}})对数据进行劫持。
(注意1,要为对象的每个属性添加get和set方法,实现对于数据的监听。)
(注意2:对象里面可能还包含着对象,因此要使用递归,为全部对象中的属性添加get和set方法)
(注意3:set方法用于修改数据,有可能修改后的值也是一个对象,因此要在set方法中,对于新修改的属性,调用Observer(newValue),为可能的对象属性添加set和get方法。)
在get中要实现的功能是:调用get,如果Dependency.temp不为空,就将其(订阅者)添加到依赖。(后面就知道为什么设置Dependency,temp了)
在set中要实现的功能是:调用Observer(newValue)。因为数据修改了,因此要通知订阅者(dependency.notify())调用相应的更新函数。
(2)vue数据的双向绑定要完成的是 数据改变视图,视图改变数据。因此需要一个模板编译类,对模板进行解析。
①使用document.querySelector(element)获取el对应的节点
②创建文档碎片document.createDocumentFragment(),将element中全部的孩子节点加入到文档碎片中。(使用文档碎片的优点:全部修改好后再渲染,减少了渲染次数。)
③ 对文档碎片中的节点进行解析:
- 使用正则表达式 解析出带有 插值表达式{{}}的文本节点(文本节点对应的nodeType为3),并为该文本节点添加一个订阅者(watcher),数据更新的时候,即修改对应的插值表达式中的值。
(注意1:因为第一次修改以后,文本节点就不再具有插值表达式了{{}},因此,先用xxx存起来,后续直接修改xxx的插值表达式{{}}中的值就可以了。)
(注意2:可能得到的属性名是more.like这种,因此要使用reduce得到最后的数值value= result_regex[1].split('.').reduce((x,y)=>x[y],vm.$data))
(注意2:因为节点中会套节点,因此,这里也要使用递归,对节点就行解析node.childNodes.forEach(child => fragment_compile(child)))
(1)Observer



