• Virtual DOM 系列三:Diff算法


    DOM操作是昂贵的,为了减少DOM操作,才有了Virtual DOM。而Virtual DOM的关键就是通过对比新旧vnode,找出差异部分来更新节点。对比的关键算法就是Diff算法。

    历史由来:

    diff算法历史悠久,并不是虚拟dom提出来的。早在linux系统中,就有diff命令,用于比较两个文本的差异,还有一个最常用的就是git diff命令,由于比较两个版本之间的差异。Virtual DOM的算法是用来对比新旧虚拟dom的差异。

    核心逻辑:

    1. creatElement

    首先先来分析patch函数的第一种用法:patch(container, vnode).。如何把虚拟dom转化成真正的DOM?

    假设每个节点都包含tag,props,children三个属性(按最简单的情况考虑)

    step 1: 创建节点;

    step 2: 设置属性;

    step 3; 遍历子节点,子节点也需要结果step1,2,然后加到当前节点中。

    经过分析,我们发现创键DOM,需要用到递归。

    代码模拟如下:

    function createElement(vnode) {
      var tag = vnode.tag;//获取元素的标签
      var props = vnode.props || {};//获取元素的属性
      var children = vnode.children || [];//获取子节点
    
      if (!tag) {
        return null;
      }
    
      var ele = document.createElement(tag);//step1:创建元素
      // step2:设置属性
      var attrName;
      for (attrName in props) {
        if (props.hasOwnProperty(attrName)) {
          ele.setAttribute(attrName, props[attrName])
        }
      }
      //step3:深度遍历子元素,并插入当前节点
      children.forEach(element => {
        ele.appendChild(createElement(element)); //递归调用
      });
      return ele;
    }

    2. updateChild

    接着再来分析一下patch函数的第二种用法:patch(oldVnode, newVnode)。如何找出新旧节点的差异,并更新节点?

    假设只考虑最简单的情况,只改变以下<li>标签的值。

    function updateChild(vnode,newVnode) {
      var oldchild = vnode.children || [];
      var newchild = newVnode.children || [];
    
      oldchild.forEach(function (childItem, index) {
        var newChildItem = newchild[index]; //假设层级相同
        if(newChildItem.tag === childItem.tag) {
          updateChild(childItem, newChildItem) //如果相同则递归遍历
        } else {
          replaceNode(childItem, newChildItem)//否则替换dom
        }
      })
    }
    function replaceNode(parantNode, oldchildNode, newChildNode) {
      var oldelem = oldchildNode.elem; //获取真实dom
      var newElem = newChildNode.elem;
      //替换dom
      parantNode.replaceChild(newElem,oldelem);
    }

    注:以上代码都是伪代码,只考虑了最简单的情况。

    总结:

    实际diff算法非常复杂,还需考虑节点的新增,删除;节点的重新排序;节点属性、样式、事件的绑定等。

    1. virtual dom是什么?为何使用VD?

    虚拟DOM

    用JS模拟DOM结构

    DOM操作非常昂贵

    将DOM对比放在JS层,提高效率

    2. 核心API

    h('<html 标签名>',{属性},[children])//含有子节点的

    h('<html 标签名>',{属性},'text'])//没有子节点,只有文本,如<p>this is VN</p>

    patch(container, vnode)//初次渲染

    patch(oldVnode, newVnode); //re-render

    3. diff算法

    creatElement,updateChild逻辑

  • 相关阅读:
    【python】turtle龟绘制开了花朵的树,程序画图
    【python】一行代码,使用pychorus提取音乐高潮部分
    【python】自动打开指定软件
    【VBA】用excel玩游戏,俄罗斯方块
    【python】3行代码搞定音频剪辑,入门版
    【python】3分钟搞定音频剪辑,进阶版
    【python】一键生成漂亮的节日快乐词云图
    【python】python学习之循环语句,小实验:九九乘法表
    【python】python学习之条件语句,小实验:商品打折后价格
    【python】使用webdriver在网页输入关键词并截屏
  • 原文地址:https://www.cnblogs.com/charliePU/p/10791200.html
Copyright © 2020-2023  润新知