1-2 【数据驱动】:真实 DOM 与 虚拟 DOM 相互转化

148 阅读1分钟

一、代码如下

<body>
  <div id="root">
    <div>
      <div class="boxf" title="内容">
        <p style="font-size: 24px;" id="section">hello</p>
        <p>hello</p>
        <p>hello</p>
      </div>
      <ul>
        <li>1</li>
        <li>2</li>
        <li style="color: blue;">3</li>
      </ul>
    </div>
  </div>

  <script>
    // 真实 DOM 转化成 虚拟 DOM
    class Vnode {
      /**
       * tag 表示元素节点元素名称nodeName,例如 div; 文本节点 nodeName 值为 undefined
       * data 表示元素节点上的 属性对象,例如{title: '123', id: 'box'}; 文本节点 没有属性
       * value 表示文本节点的 nodeValue; 元素节点的 nodeValue 为 undefined
       * type 表示节点的类型,元素节点的 nodeType 值为 1, 文本节点的 nodeType 值为 3
       */
      constructor(tag, data, value, type) {
        // 文本节点没有 nodeName, 所以 tag 要进行 判断,不然会报错
        this.tag = tag && tag.toLowerCase();
        this.data = data;
        this.value = value;
        this.type = type;
        this.children = [];
      }
      
      // 加上子节点的虚拟 DOM
      appendChild(vNode) {
        this.children.push(vNode);
      }
    }

    // 把真实 DOM 转化成 虚拟 DOM
    function getVnode(node) {
      let nodeType = node.nodeType;
      let _vnode = null;
      if (nodeType === 1) {
        // 元素节点
        let NodeName = node.nodeName;
        let attrs = node.attributes;
        let attrsObj = {};
        for (var i = 0; i < attrs.length; i++) {
          attrsObj[attrs[i].nodeName] = attrs[i].nodeValue;
        }
        _vnode = new Vnode(NodeName, attrsObj, undefined, nodeType);
        let childNodes = node.childNodes;
        for (var i = 0; i < childNodes.length; i++) {
          _vnode.appendChild(getVnode(childNodes[i]))
        }
      } else if (nodeType == 3) {
        _vnode = new Vnode(undefined, undefined, node.nodeValue, nodeType);
      }

      return _vnode;
    }

    let root = document.querySelector('#root');
    let rootVnode = getVnode(root);
    console.log(rootVnode, '虚拟 Dom')

    // 把虚拟 DOM 转化成真实 DOM
    function parseVnode(vnode) {
      let type = vnode.type;
      let _node = null;
      if (type == 3) {
        return document.createTextNode(vnode.value);
      } else if (type == 1) {
        // 创建一个元素节点
        _node = document.createElement(vnode.tag);
        // 给元素节点添加属性
        let attrs = vnode.data;
        Object.keys(attrs).forEach(key => {
          let attrName = key;
          let attrValue = attrs[key];
          _node.setAttribute(attrName, attrValue);
        })
        // 给元素节点添加子元素节点
        let childrenNodes = vnode.children;
        for (var i = 0; i < childrenNodes.length; i++) {
          _node.appendChild(parseVnode(childrenNodes[i]))
        }
      }
      return _node;
    }
    let dom = parseVnode(rootVnode);
    console.log(dom, '真实 Dom')
  </script>
</body>

二、真实 DOM 转 虚拟 DOM 结果如下

image.png

三、虚拟 DOM 转 真实 DOM 结果如下

转真实后的 DOM 跟我们上面的 body 中的元素一致。

image.png

image.png