防Vue系列-07 将前几篇的代码知识点进行整合

Vue解析总纲
上一节:防Vue系列-06 了解函数柯里化

本篇主要讲之前的代码的知识点,进行整合

这里我们用combine替换之前的compiler
combine用来合并数据与带有{{}}虚拟的Dom
compiler用来合并数据与带有{{}}真实的Dom

<div id="root">
  <p>{{ name.firstName }}</p>
</div>
// ==========================combine函数 合并数据与带有{{}}虚拟的Domdom===================================s
 //解析data.xxx.xx
      /**
       *@params obj:Object  data:{nama:{firstName:'小',lastName:'陈'}}
       *@params path:String 'xxx.xxx'
       *@return res:any
       */
      function getValueByPath(data, path) {
        let paths = path.split(".");
        //[name, firstName];
        let res = data;
        //循环查找
        for (let index = 0; index < paths.length; index++) {
          res = res[paths[index]];
        }
        // res === '小'
        return res;
      }
      //正则,用来匹配{{}}
      let r = /\{\{(.+?)\}\}/g;
      // 带坑的vnode和数据 合并 生成带数据vnode
      /**
       *@params vnode:VNode (带有{{}}的虚拟dom)
       *@params data:Object(数据源)
       *@return _vnode:VNode(带有数据的虚拟dom)
       */

      function combine(vnode, data) {
        let {
          tag: _tag,
          data: _data,
          value: _value,
          type: _type,
          children: _children,
        } = vnode;
        let _vnode = null;
        if (_type === 3) {
          //文本节点 判断 是否有{{}}
          _value = _value.replace(r, (_, g) => {
            let key = g.trim();
            let value = getValueByPath(data, key);
            return value;
          });
          _vnode = new VNode(_tag, _data, _value, _type);
        } else if (_type === 1) {
          _vnode = new VNode(_tag, _data, _value, _type);
          _children.forEach((element) => {
            _vnode.appendChild(combine(element, data));
          });
        }
        return _vnode;
      }
      /*



// ==========================paraseVnode函数 虚拟dom转真实dom===================================
 *@params tag:String  'div||span||h1'
 *@params data:Object '{id:'root,class:'theme'...}'
 *@params value:String 'nodeValue || undefined'
 *@params type:Number 'nodeType=1 || 2 ||3 '
 *@params children:Array<Vnode> 
 @return dom:HtmlElement 
 */
      function createElement(tag, data, value, type, children) {
        let dom; //定义储存dom变量
        // 元素节点
        if (type === 1) {
          //创建元素
          dom = document.createElement(tag);
          //添加属性
          for (const key in data) {
            if (data.hasOwnProperty.call(data, key)) {
              dom.setAttribute(key, data[key]);
            }
          }
          // 存在子节点遍历循环递归
          if (children) {
            for (let index = 0; index < children.length; index++) {
              let nodeTag = children[index].tag;
              let nodeData = children[index].data;
              let nodeValue = children[index].value;
              let nodeType = children[index].type;
              let nodeChildren = children[index].children;
              dom.appendChild(
                createElement(
                  nodeTag,
                  nodeData,
                  nodeValue,
                  nodeType,
                  nodeChildren
                )
              );
            }
          }
        }
        // 文本节点,创建文本节点
        else if (type === 3) {
          dom = document.createTextNode(value);
        }
        return dom;
      }

      /*
 *@params vnode:Object
 @return dom:HtmlElement 
 */
      function paraseVnode(vnode) {
        return createElement(
          vnode.tag,
          vnode.data,
          vnode.value,
          vnode.type,
          vnode.children
        );
      }

      // ==========================getVNode函数 真实dom转虚拟dom===================================
      /*
       *@params tag:String  'div||span||h1'
       *@params data:Object '{id:'root,class:'theme'...}'
       *@params value:String 'nodeValue || undefined'
       *@params type:Number 'nodeType=1 || 2 ||3 '
       */
      class VNode {
        constructor(tag, data, value, type) {
          this.tag = tag && tag.toLocaleLowerCase();
          this.data = data;
          this.value = value;
          this.type = type;
          this.children = []; //子节点数组,默认[]
        }
        // 添加子节点
        appendChild(childrenNode) {
          this.children.push(childrenNode);
        }
      }
      /*
       *@params realDom:HtmlElement  '真实的DOM对象'
       *@return vNode:Object '虚拟的DOM对象'
       */
      function getVNode(realDom) {
        let nodeType = realDom.nodeType; //节点类型
        let _vode = null;
        // 元素节点
        if (nodeType === 1) {
          let tag = realDom.nodeName; //标签名
          let attributes = realDom.attributes; //对象属性
          let childNodes = realDom.childNodes; //子节点
          // 获取属性对象
          let data = {};
          for (let i = 0; i < attributes.length; i++) {
            let key = attributes[i].nodeName;
            let value = attributes[i].value;
            data[key] = value;
          }
          // 生成虚拟dom对象
          _vode = new VNode(tag, data, undefined, nodeType);
          //如果有子节点,添加子节点,递归遍历  ===本节难点!!!===
          for (let i = 0; i < childNodes.length; i++) {
            _vode.appendChild(getVNode(childNodes[i]));
          }
        }
        // 文本节点
        else if (nodeType === 3) {
          _vode = new VNode(undefined, undefined, realDom.nodeValue, nodeType);
        }
        return _vode; //虚拟dom
      }

      // ==========================Vue构造函数===================================
      function Vue(options) {
        // 内部数据使用_ 开头 ,只读数据$开头
        this._data = options.data;
        this._el = options.el;
        //准备工作(模板)
        this.$el = this._templateNode = document.querySelector(this._el);//获取挂载的对象
        this._parent = this._templateNode.parentNode;//父节点
        //挂载
        this.mount();
      }
      //挂载
      Vue.prototype.mount = function () {
        this.render = this.createRenderFn(); //生成带有data数据的vnode
        //挂载dom
        this.mountComponet();
      };
      // 函数颗粒化,缓存带有{{}}的vnode
      Vue.prototype.createRenderFn = function () {
        //带坑的虚拟dom
        let ast = getVNode(this.$el);
        return function () {
          // 生成带数据vnode
          let combineData = combine(ast, this._data);
          return combineData;
        };
      };
      //这里就是以后当数据发生变化watcher来进行调用  更新组件vue diff算法就在这里
      Vue.prototype.mountComponet = function () {
        this.updata(this.render());
      };
      // 更新dom 到页面
      Vue.prototype.updata = function (vnode) {
      	//将带有数据的vnode转成真实的dom
        let realDom = paraseVnode(vnode);
        //这里我们直接操作dom替换了,后面再细讨论
        this.$el.parentNode.replaceChild(realDom, this.$el);
      };
      // 创建Vue的实例
      const vm = new Vue({
        el: "#root",
        data: {
          name: {
            firstName: "小",
            lastName: "陈",
          },
        },
      });
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值