博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Virtual DOM 系列三:Diff算法
阅读量:5230 次
发布时间:2019-06-14

本文共 2067 字,大约阅读时间需要 6 分钟。

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逻辑

转载于:https://www.cnblogs.com/charliePU/p/10791200.html

你可能感兴趣的文章
一个poi操作实现导出功能的类
查看>>
公用的工具类不应该有公共的构造函数
查看>>
声纹识别 ====飞讯
查看>>
可跨平台C++开源图形图像框架:openFrameworks
查看>>
[bzoj3404] [Usaco2009 Open]Cow Digit Game又见数字游戏
查看>>
1053: [HAOI2007]反素数ant - BZOJ
查看>>
Pad控件 UIPopoverController的介绍与使用(Pad的专属菜单控件、Swift版本)
查看>>
ARM v7-A 系列CPU的MMU隐射分析
查看>>
NPM install -save 和 -save-dev 区别
查看>>
2017免费获取正版win10的方法
查看>>
将已有项目推送到github上
查看>>
要找个合适的WEB UI组件真纠结
查看>>
止步,你就输了
查看>>
对于公司最近一次技术分享的总结
查看>>
Luogu2737 USACO4.1麦香牛块(动态规划)
查看>>
卸载RedHat7自带的yum,安装并使用网易163源
查看>>
简单的做一个旋转正六面体吧
查看>>
Building products with javascript - Redux and Redux-Observable
查看>>
覆盖equals时请遵守通用约定
查看>>
第一次团队作业
查看>>