来至小白写的文章:

先把小白写的双向数据绑定 三篇文章 的步骤贴上来:

渲染
1创建代码片段,
2.1将节点遍历进代码片段
2.2同时遍历的节点进入代码解析器,
3判断节点类型
3.1标签类型 解析器遍历代码的属性
3.2 文本类型
3.3判断含有相对应指令或模板
3.4 如果有则对view视图进行赋值

3.5完事之后将代码片段插入vue绑定节点


响应数据绑定
4.1创建监听器,进行数据劫持和监听
3.4.1 接3.4 对当前节点进行事件的监听
4.2当数据改变时,改变vm一级下的数据,进行赋值,因为劫持的数据在vm的一级根下,这时触发监听器
4.3监听器,数据改变,触发set方法,给vm.data相对应数据赋值

 

实现数据双向绑定
当前背景,只是input改变改变model也就是data中的数据,实现了单向的绑定,如何通过model,data的数据改变来改变视图view呢?

采用 发布/订阅者模式

5 创建一个订阅器Dep
6 创建一个订阅者Watcher(可以接收信息,更新渲染自身和添加进订阅器),会自调用自身的方法update,update的方法会对view层进行赋值渲染
6.1 watcher中的update方法会触发get方法从而会触发监听器中的get方法,此时会往订阅器添加订阅者
3.2.1 判断节点类型,对相对应的节点进行赋值 所以3.4步骤在此废弃

当 observe 监听器中监听数据改变时,调用订阅器的 notify 方法遍历通知所有订阅者

 

<div id="app"><input type="text" v-model="text" value="123">{{text}}{{name}}</div>
  <script>/**
     *  使用documentfragment处理节点速度和性能要高于直接操作dom。vue编译的时候,
    就是将挂载目标的所有子节点劫持到documentfragment中,经过处理后再将documentfragment整体返回到挂载目标中。
*/ // DocumentFragment(文档片段,节点容器) 劫持vue挂载的所有节点 function nodeToFragment(node, vm) { //创建代码片段 var flag = document.createDocumentFragment(); var child; while(child = node.firstChild) { compile(child,vm); //appendChild 会删掉所有原来的节点 flag.appendChild(child); //劫持node的所有节点 } return flag; } // 指令解析 function compile(node, vm) { //这里讲解一下,nodeType等于1说明节点是标签,所有解析标签所有的属性;
    nodeType等于3说明节点是文本,可以操作文本的文本名和值(node.nodeName,node.nodeValue)
if(node.nodeType ===1) { var attr = node.attributes; // 获取所有属性 // 解析属性 for(var i in attr) { if(attr.hasOwnProperty(i)) { if(attr[i].name === "v-model") { let name = attr[i].value; node.value = vm.data[name]; node.removeAttribute('v-modle'); node.addEventListener('input',function(event) { // 给相应的data属性赋值,进而触发该属性的set方法 //注意这里是给vm一级下的数据赋值,因为劫持的数据在vm的一级根下 //这里会促发监听器,从而改变 data 中的数据 vm[name] = event.target.value }) } } } } let res = /\{\{(.+?)\}\}/g; if(node.nodeType === 3) { //文本节点没有 attributes if(res.test(node.nodeValue)){ let name = RegExp.$1; name = name.trim(); log(name); node.nodeValue = vm.data[name]; } } } class Vue { constructor(opt){ this.el = document.querySelector(opt.el); this.data = opt.data; let dom = nodeToFragment(this.el,this); this.el.appendChild(dom); //代码片段插入vue绑定节点 } } let vm = new Vue({ el:'#app', data: { text: 'hello world' } });

 贴完代码,顺便讲解一下

1创建代码片段,
2.1将节点遍历进代码片段
2.2同时遍历的节点进入代码解析器,
3判断节点类型
3.1标签类型 解析器遍历代码的属性 
3.2 文本类型 
3.3判断含有相对应指令或模板
3.4 如果有则对view视图进行赋值

3.5完事之后将代码片段插入vue绑定节点

 

DocumentFragment,文档片段接口,一个没有父对象的最小文档对象。它被作为一个轻量版的 Document 使用,就像标准的document一样,存储由节点(nodes)组成的文档结构。与document相比,最大的区别是DocumentFragment 不是真实 DOM 树的一部分,它的变化不会触发 DOM 树的重新渲染,且不会导致性能等问题。

最常用的方法是使用文档片段作为参数(例如,任何 Node 接口类似 Node.appendChild 和 Node.insertBefore 的方法),这种情况下被添加(append)或被插入(inserted)的是片段的所有子节点, 而非片段本身。因为所有的节点会被一次插入到文档中,而这个操作仅发生一个重渲染的操作,而不是每个节点分别被插入到文档中,因为后者会发生多次重渲染的操作。

使用documentfragment处理节点速度和性能要高于直接操作dom。vue编译的时候,就是将挂载目标的所有子节点劫持到 documentfragment 中,经过处理后再将 documentfragment 整体返回到挂载目标中。
说白了 DocumentFragment 就是不会导致重排(回流)
 
其它的不说了,都是一些JS基础的语法,不会的留言,虽然我也不一定会。。。
posted on 2021-01-29 12:10  京鸿一瞥  阅读(294)  评论(0)    收藏  举报