前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【JS】204-让虚拟DOM和DOM-diff不再成为你的绊脚石

【JS】204-让虚拟DOM和DOM-diff不再成为你的绊脚石

作者头像
pingan8787
发布于 2019-07-23 10:19:00
发布于 2019-07-23 10:19:00
85600
代码可运行
举报
文章被收录于专栏:前端自习课前端自习课
运行总次数:0
代码可运行

编者按:本文转载自chenhongdong的掘金专栏

Keep Moving

时至今日,前端对于知识的考量是越来越有水平了,逼格高大上了

各类框架大家已经可以说无论是工作还是日常中都已经或多或少的使用过了

曾经听说很多人被问到过虚拟DOM和DOM-diff算法是如何实现的,有没有研究过?

想必问出此问题的也是高手高手之高高手了,很多人都半开玩笑的说:“面试造航母,工作拧螺丝”

那么,话不多说了,今天就让我们也来一起研究研究这个东东

好饭不怕晚,沉淀下来收收心!我们虽然走的慢,但是却从未停下脚步

神奇的虚拟DOM

首先神奇不神奇的我们先不去关注,先来简单说说何为虚拟DOM

虚拟DOM简而言之就是,用JS去按照DOM结构来实现的树形结构对象,你也可以叫做DOM对象

好了,一句话就把这么伟大的东西给解释了,那么不再耽误时间了,赶紧进入主环节吧

当然,这里还有整个项目的地址方便查看https://github.com/chenhongdong/article/tree/develop/%E8%99%9A%E6%8B%9Fdom/dom-diff。

实现一下虚拟DOM

在亲自上阵之前,我们让粮草先行,先发个图,来看一下整个目录结构是什么样子的

这个目录结构是用create-react-app脚手架直接生成的,也是为了方便编译调试

代码语言:javascript
代码运行次数:0
运行
复制
// 全局安装npm i create-react-app -g// 生成项目create-react-app dom-diff// 进入项目目录cd dom-diff// 编译npm run start

现在我们开始正式写吧,从创建虚拟DOM及渲染DOM起步吧

创建虚拟DOM

在element.js文件中要实现如何创建虚拟DOM以及将创建出来的虚拟DOM渲染成真实的DOM

首先实现一下如何创建虚拟DOM,看代码:

代码语言:javascript
代码运行次数:0
运行
复制
// element.js
// 虚拟DOM元素的类,构建实例对象,用来描述DOMclass Element {    constructor(type, props, children) {        this.type = type;        this.props = props;        this.children = children;    }}// 创建虚拟DOM,返回虚拟节点(object)function createElement(type, props, children) {    return new Element(type, props, children);}
export {    Element,    createElement}

写好了方法,我们就从index.js文件入手来看看是否成功吧

调用createElement方法

在主入口文件里,我们主要做的操作就是来创建一个DOM对象,渲染DOM以及通过diff后去打补丁更新DOM,不啰嗦了,直接看代码:

代码语言:javascript
代码运行次数:0
运行
复制
// index.js
// 首先引入对应的方法来创建虚拟DOMimport { createElement } from './element';
let virtualDom = createElement('ul', {class: 'list'}, [    createElement('li', {class: 'item'}, ['周杰伦']),    createElement('li', {class: 'item'}, ['林俊杰']),    createElement('li', {class: 'item'}, ['王力宏'])]);
console.log(virtualDom);

createElement方法也是vue和react用来创建虚拟DOM的方法,我们也叫这个名字,方便记忆。接收三个参数,分别是typepropschildren

参数分析:

  • type: 指定元素的标签类型,如'li', 'div', 'a'等
  • props: 表示指定元素身上的属性,如class, style, 自定义属性等
  • children: 表示指定元素是否有子节点,参数以数组的形式传入

下面来看一下打印出来的虚拟DOM,如下图

到目前为止,已经轻而易举的实现了创建虚拟DOM。那么,接下来进行下一步,将其渲染为真实的DOM,别犹豫,继续回到element.js文件中

渲染虚拟DOM

代码语言:javascript
代码运行次数:0
运行
复制
// element.js
class Element {    // 省略}
function createElement() {    // 省略}
// render方法可以将虚拟DOM转化成真实DOMfunction render(domObj) {    // 根据type类型来创建对应的元素    let el = document.createElement(domObj.type);
    // 再去遍历props属性对象,然后给创建的元素el设置属性    for (let key in domObj.props) {        // 设置属性的方法        setAttr(el, key, domObj.props[key]);    }
    // 遍历子节点    // 如果是虚拟DOM,就继续递归渲染    // 不是就代表是文本节点,直接创建    domObj.children.forEach(child => {        child = (child instanceof Element) ? render(child) : document.createTextNode(child);        // 添加到对应元素内        el.appendChild(child);    });
    return el;}
// 设置属性function setAttr(node, key, value) {    switch(key) {        case 'value':            // node是一个input或者textarea就直接设置其value即可            if (node.tagName.toLowerCase() === 'input' ||                node.tagName.toLowerCase() === 'textarea') {                node.value = value;            } else {                node.setAttribute(key, value);            }            break;        case 'style':            // 直接赋值行内样式            node.style.cssText = value;            break;        default:            node.setAttribute(key, value);            break;    }}
// 将元素插入到页面内function renderDom(el, target) {    target.appendChild(el);}
export {    Element,    createElement,    render,    setAttr,    renderDom};

既然写完了,那就赶快来看看成果吧

调用render方法

再次回到index.js文件中,修改为如下代码

代码语言:javascript
代码运行次数:0
运行
复制
// index.js
// 引入createElement、render和renderDom方法import { createElement, render, renderDom } from './element';
let virtualDom = createElement('ul', {class: 'list'}, [    createElement('li', {class: 'item'}, ['周杰伦']),    createElement('li', {class: 'item'}, ['林俊杰']),    createElement('li', {class: 'item'}, ['王力宏'])]);
console.log(virtualDom);
// +++let el = render(virtualDom); // 渲染虚拟DOM得到真实的DOM结构console.log(el);// 直接将DOM添加到页面内renderDom(el, document.getElementById('root'));

通过调用render方法转为真实DOM,并调用renderDom方法直接将DOM添加到了页面内

下图为打印后的结果:

截止目前,我们已经实现了虚拟DOM并进行了渲染真实DOM到页面中。那么接下来我们就有请DOM-diff隆重登场,来看一下这大有来头的diff算法是如何发光发热的吧!

DOM-diff闪亮登场

说到DOM-diff那一定要清楚其存在的意义,给定任意两棵树,采用先序深度优先遍历的算法找到最少的转换步骤

DOM-diff比较两个虚拟DOM的区别,也就是在比较两个对象的区别。

作用: 根据两个虚拟对象创建出补丁,描述改变的内容,将这个补丁用来更新DOM

已经了解到DOM-diff是干嘛的了,那就没什么好说的了,继续往下写吧

代码语言:javascript
代码运行次数:0
运行
复制
// diff.js
function diff(oldTree, newTree) {    // 声明变量patches用来存放补丁的对象    let patches = {};    // 第一次比较应该是树的第0个索引    let index = 0;    // 递归树 比较后的结果放到补丁里    walk(oldTree, newTree, index, patches);
    return patches;}
function walk(oldNode, newNode, index, patches) {    // 每个元素都有一个补丁    let current = [];
    if (!newNode) { // rule1        current.push({ type: 'REMOVE', index });    } else if (isString(oldNode) && isString(newNode)) {        // 判断文本是否一致        if (oldNode !== newNode) {            current.push({ type: 'TEXT', text: newNode });        }
    } else if (oldNode.type === newNode.type) {        // 比较属性是否有更改        let attr = diffAttr(oldNode.props, newNode.props);        if (Object.keys(attr).length > 0) {            current.push({ type: 'ATTR', attr });        }        // 如果有子节点,遍历子节点        diffChildren(oldNode.children, newNode.children, patches);    } else { // 说明节点被替换了        current.push({ type: 'REPLACE', newNode});    }
    // 当前元素确实有补丁存在    if (current.length) {        // 将元素和补丁对应起来,放到大补丁包中        patches[index] = current;    }}
function isString(obj) {    return typeof obj === 'string';}
function diffAttr(oldAttrs, newAttrs) {    let patch = {};    // 判断老的属性中和新的属性的关系    for (let key in oldAttrs) {        if (oldAttrs[key] !== newAttrs[key]) {            patch[key] = newAttrs[key]; // 有可能还是undefined        }    }
    for (let key in newAttrs) {        // 老节点没有新节点的属性        if (!oldAttrs.hasOwnProperty(key)) {            patch[key] = newAttrs[key];        }    }    return patch;}
// 所有都基于一个序号来实现let num = 0;
function diffChildren(oldChildren, newChildren, patches) {    // 比较老的第一个和新的第一个    oldChildren.forEach((child, index) => {        walk(child, newChildren[index], ++num, patches);    });}
// 默认导出export default diff;

代码虽然又臭又长,但是这些代码就让我们实现了diff算法了,所以大家先不要盲动,不要盲动,且听风吟,让我一一道来

比较规则

  • 新的DOM节点不存在{type: 'REMOVE', index}
  • 文本的变化{type: 'TEXT', text: 1}
  • 当节点类型相同时,去看一下属性是否相同,产生一个属性的补丁包{type: 'ATTR', attr: {class: 'list-group'}}
  • 节点类型不相同,直接采用替换模式{type: 'REPLACE', newNode}

根据这些规则,我们再来看一下diff代码中的walk方法这位关键先生

walk方法都做了什么?

  • 每个元素都有一个补丁,所以需要创建一个放当前补丁的数组
  • 如果没有new节点的话,就直接将type为REMOVE的类型放到当前补丁里

代码语言:javascript
代码运行次数:0
运行
复制
if (!newNode) {  current.push({ type: 'REMOVE', index });}
  • 如果新老节点是文本的话,判断一下文本是否一致,再指定类型TEXT并把新节点放到当前补丁

代码语言:javascript
代码运行次数:0
运行
复制
else if (isString(oldNode) && isString(newNode)) {        if (oldNode !== newNode) {            current.push({ type: 'TEXT', text: newNode });        }    }
  • 如果新老节点的类型相同,那么就来比较一下他们的属性props
    • 遍历oldChildren,然后递归调用walk再通过child和newChildren[index]去diff
    • 去比较新老Attr是否相同
    • 把newAttr的键值对赋给patch对象上并返回此对象
    • 属性比较 diffAttr
    • 然后如果有子节点的话就再比较一下子节点的不同,再调一次walk diffChildren

代码语言:javascript
代码运行次数:0
运行
复制
else if (oldNode.type === newNode.type) {        // 比较属性是否有更改        let attr = diffAttr(oldNode.props, newNode.props);        if (Object.keys(attr).length > 0) {            current.push({ type: 'ATTR', attr });        }
        // 如果有子节点,遍历子节点        diffChildren(oldNode.children, newNode.children, patches);    }
  • 上面三个如果都没有发生的话,那就表示节点单纯的被替换了,type为REPLACE,直接用newNode替换即可

代码语言:javascript
代码运行次数:0
运行
复制
else {        current.push({ type: 'REPLACE', newNode});    }
  • 当前补丁里确实有值的情况,就将对应的补丁放进大补丁包里

代码语言:javascript
代码运行次数:0
运行
复制
if (current.length > 0) {        // 将元素和补丁对应起来,放到大补丁包中        patches[index] = current;    }

以上就是关于diff算法的分析过程了,没太明白的话没关系,再反复看几遍试试,意外总是不期而遇的

diff已经完事了,那么最后一步就是大家所熟知的打补丁

补丁要怎么打?那么让久违的patch出来吧

patch补丁更新

打补丁需要传入两个参数,一个是要打补丁的元素,另一个就是所要打的补丁了,那么直接看代码

代码语言:javascript
代码运行次数:0
运行
复制
import { Element, render, setAttr } from './element';
let allPatches;let index = 0; // 默认哪个需要打补丁
function patch(node, patches) {    allPatches = patches;
    // 给某个元素打补丁    walk(node);}
function walk(node) {    let current = allPatches[index++];    let childNodes = node.childNodes;
    // 先序深度,继续遍历递归子节点    childNodes.forEach(child => walk(child));
    if (current) {        doPatch(node, current); // 打上补丁    }}
function doPatch(node, patches) {    // 遍历所有打过的补丁    patches.forEach(patch => {        switch (patch.type) {            case 'ATTR':                for (let key in patch.attr) {                    let value = patch.attr[key];                    if (value) {                        setAttr(node, key, value);                    } else {                        node.removeAttribute(key);                    }                }                break;            case 'TEXT':                node.textContent = patch.text;                break;            case 'REPLACE':                let newNode = patch.newNode;                newNode = (newNode instanceof Element) ? render(newNode) : document.createTextNode(newNode);                node.parentNode.replaceChild(newNode, node);                break;            case 'REMOVE':                node.parentNode.removeChild(node);                break;            default:                break;        }    });}
export default patch;

看完代码还需要再来简单的分析一下

patch做了什么?

  • 用一个变量来得到传递过来的所有补丁allPatches
  • patch方法接收两个参数(node, patches)
    • 在方法内部调用walk方法,给某个元素打上补丁
  • walk方法里获取所有的子节点
    • 给子节点也进行先序深度优先遍历,递归walk
    • 如果当前的补丁是存在的,那么就对其打补丁(doPatch)
  • doPatch打补丁方法会根据传递的patches进行遍历
    • 判断补丁的类型来进行不同的操作: 1. 属性ATTR for in去遍历attrs对象,当前的key值如果存在,就直接设置属性setAttr; 如果不存在对应的key值那就直接删除这个key键的属性2. 文字TEXT 直接将补丁的text赋值给node节点的textContent即可3. 替换REPLACE 新节点替换老节点,需要先判断新节点是不是Element的实例,是的话调用render方法渲染新节点;不是的话就表明新节点是个文本节点,直接创建一个文本节点就OK了。之后再通过调用父级parentNode的replaceChild方法替换为新的节点4. 删除REMOVE 直接调用父级的removeChild方法删除该节点
  • 将patch方法默认导出方便调用

好了,一切都安静下来了。让我们回归index.js文件中,去调用一下diff和patch这两个重要方法,看看奇迹会不会发生吧

回归

代码语言:javascript
代码运行次数:0
运行
复制
// index.jsimport { createElement, render, renderDom } from './element';// +++ 引入diff和patch方法import diff from './diff';import patch from './patch';// +++
let virtualDom = createElement('ul', {class: 'list'}, [    createElement('li', {class: 'item'}, ['周杰伦']),    createElement('li', {class: 'item'}, ['林俊杰']),    createElement('li', {class: 'item'}, ['王力宏'])]);
let el = render(virtualDom);renderDom(el, window.root);
// +++// 创建另一个新的虚拟DOMlet virtualDom2 = createElement('ul', {class: 'list-group'}, [    createElement('li', {class: 'item active'}, ['七里香']),    createElement('li', {class: 'item'}, ['一千年以后']),    createElement('li', {class: 'item'}, ['需要人陪'])]);// diff一下两个不同的虚拟DOMlet patches = diff(virtualDom, virtualDom2);console.log(patches);// 将变化打补丁,更新到elpatch(el, patches);

将修改后的代码保存,会在浏览器里看到DOM被更新了,如下图

到这里就finish了,内容有些多,可能不是很好的消耗,不过没关系,就让我用最后几句话来总结一下实现的整个过程吧

四句话

我们来梳理一下整个DOM-diff的过程:

  1. 用JS对象模拟DOM(虚拟DOM)
  2. 把此虚拟DOM转成真实DOM并插入页面中(render)
  3. 如果有事件发生修改了虚拟DOM,比较两棵虚拟DOM树的差异,得到差异对象(diff)
  4. 把差异对象应用到真正的DOM树上(patch)

行了,就这四句话吧,说多了就有点画蛇添足了。好久没有写文章了,很感谢小伙伴们的观看,辛苦各位了,886。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-04-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端自习课 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Vue 虚拟 DOM 的本质与引入原因详解及示例代码
Vue里的虚拟DOM是一种对真实DOM的抽象表示,其结构通常为一个 JavaScript 对象,其内保存了DOM节点的标签、属性、子节点等信息。这种抽象表示能够在内存中高效地进行更新与比较,从而在数据发生改变时,只对需要更新的部分进行真正的DOM操作。虚拟DOM的设计理念源于对真实DOM操作性能问题的反思,因为真实DOM操作通常需要频繁地进行重绘与重排,消耗资源且性能开销较大。
编程小妖女
2025/04/24
1330
Vue 虚拟 DOM 的本质与引入原因详解及示例代码
# 虚拟 DOM 之 Diff 算法
上一节讲了虚拟 DOM,但是虚拟 DOM 是如何更新的?新旧节点的 path 又是如何进行的?这都需要一个 Diff 来完成。
九旬
2023/10/18
2080
DOM-Diff讲解
我是歌谣 最好的种树是十年前 其次是现在 今天继续给大家带来的是DOM-Diff讲解
爱学习的前端歌谣
2023/10/24
1820
DOM-Diff讲解
虚拟 DOM 到底是什么?(长文建议收藏)
虚拟 DOM (Virtual DOM )这个概念相信大家都不陌生,从 React 到 Vue ,虚拟 DOM 为这两个框架都带来了跨平台的能力(React-Native 和 Weex)。因为很多人是在学习 React 的过程中接触到的虚拟 DOM ,所以为先入为主,认为虚拟 DOM 和 JSX 密不可分。其实不然,虚拟 DOM 和 JSX 固然契合,但 JSX 只是虚拟 DOM 的充分不必要条件,Vue 即使使用模版,也能把虚拟 DOM 玩得风生水起,同时也有很多人通过 babel 在 Vue 中使用 JSX。
桃翁
2019/07/08
4.4K0
虚拟 DOM 到底是什么?(长文建议收藏)
小白的diff算法试试水之旅0.前言1. 主角1:Element构造函数2. 主角2:render函数3. 大主角: diff函数4. 更新5. 完成
先介绍一下虚拟dom的数据结构,我们都知道源码里面有createElement函数,通过他创建虚拟dom,然后调用render函数。还记得VUE脚手架住入口文件那句足够装逼的h=>h(App)吗,其实就是类似createElement(App)这样子的过程。我们看一下他简单的结构:
lhyt
2018/10/31
4370
javascript基础修炼(11)——DOM-DIFF的实现
在上一篇博文《javascript基础修炼(10)——VirtualDOM和基本DFS》中第三节演示了关于如何利用Virtual-DOM的树结构生成真实DOM的部分,原本希望让不熟悉深度优先算遍历的读者先关注和感受一下遍历的基本流程,所以演示用的DOM节点只包含了类名和文本内容,结构简单,在复现DOM结构时直接拼接字符串在控制台显示出来的方式。许多读者留言表示对如何从Virtual-Dom得到真实的DOM节点仍然很困惑。
大史不说话
2018/12/25
7070
Virtual Dom和Diff算法
这是一篇很长的文章!!!坚持看到最后有彩蛋哦!!! 文章开篇,我们先思考一个问题,大家都说 virtual dom 这,virtual dom 那的,那么 virtual dom 到底是啥?
前端迷
2019/09/05
7490
Virtual Dom和Diff算法
React源码分析与实现(三):实操DOM Diff
众所周知,React中最为人称赞的就是Virtual DOM和 diff 算法的完美结合,让我们可以不顾性能的“任性”更新界面,前面文章中我们有介绍道Virtual DOM,其实就是通过js来模拟dom的实现,然后通过对js obj的操作,最后渲染到页面中,但是,如果当我们修改了一丢丢东西,就要渲染整个页面的话,性能消耗还是非常大的,如何才能准确的修改该修改的地方就是我们diff算法的功能了。
Nealyang
2019/09/29
7080
React源码分析与实现(三):实操DOM Diff
简单实现一个Virtual DOM
前言 之前写过一篇文章为什么使用v-for时必须添加唯一的key?[1],但是解释的不是很深刻,其实真正的原因还需要从Virtual DOM的实现上解释;本篇文章从简单实现一个Virtual DOM入
木子星兮
2020/07/17
8160
简单实现一个Virtual DOM
# Vue 之虚拟 DOM
然后在通过createElement等 DOM API 操作完成从 JavaScript 对象=》真实 DOM 的转化。
九旬
2023/10/18
2330
# Vue 之虚拟 DOM
虚拟DOM及其实现
一篇介绍从各个角度介绍数据变化和UI变化的文章,解析了主流的库是怎么工作的:http://teropa.info/blog/2015/03/02/change-and-its-detection-in-javascript-frameworks.html 分析了过去和现在的JS框架是怎么处理前端数据和页面更新的。
河马嘴不大
2022/12/24
3520
虚拟DOM及其实现
你不知道的Virtual DOM(二):Virtual Dom的更新
目前最流行的两大前端框架,React 和 Vue,都不约而同的借助 Virtual DOM 技术提高页面的渲染效率。那么,什么是 Virtual DOM ?它是通过什么方式去提升页面渲染效率的呢?本系列文章会详细讲解 Virtual DOM 的创建过程,并实现一个简单的 Diff 算法来更新页面。本文的内容脱离于任何的前端框架,只讲最纯粹的 Virtual DOM 。敲单词太累了,下文 Virtual DOM 一律用 VD 表示。
Dickensl
2022/06/14
4030
你不知道的Virtual DOM(二):Virtual Dom的更新
virtualdom diff算法实现分析
这两个月接触下vue ,花了两天时间了解了下vue的virtualdom实现,记录下学习心得。
用户2303251
2018/06/07
1K0
React && VUE Virtual Dom的Diff算法统一之路 snabbdom.js解读
VirtualDOM是react在组件化开发场景下,针对DOM重排重绘性能瓶颈作出的重要优化方案,而他最具价值的核心功能是如何识别并保存新旧节点数据结构之间差异的方法,也即是diff算法。毫无疑问的是diff算法的复杂度与效率是决定VirtualDOM能够带来性能提升效果的关键因素。因此,在VirtualDOM方案被提出之后,社区中不断涌现出对diff的改进算法,引用司徒正美的经典介绍:
super.x
2019/04/12
1.6K0
virtualdom diff算法实现分析
这两个月接触下vue ,花了两天时间了解了下vue的virtualdom实现,记录下学习心得。
用户2303251
2018/06/07
1.4K0
react 学习(一) 实现简版虚拟 dom 和挂载
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试的也都能答出来。但对于 react 只是有一定的了解,没有真实的学习过实现,虽然之前也看过一些文章,但是只停留在表面,因为别人这么写了,也就下意识的认为是这样。本次正好配合工作的契机,我们从零开始学习一下,使用的话呢就简单一过,相信大家也都用过或者看完官网也都了解了。如果您是大佬,欢迎批评指正;如果您是初级选手,希望能够一起学习。
测不准
2022/04/05
5780
你不知道的Virtual DOM(三):Virtual Dom更新优化
目前最流行的两大前端框架,React和Vue,都不约而同的借助Virtual DOM技术提高页面的渲染效率。那么,什么是Virtual DOM?它是通过什么方式去提升页面渲染效率的呢?本系列文章会详细讲解Virtual DOM的创建过程,并实现一个简单的Diff算法来更新页面。本文的内容脱离于任何的前端框架,只讲最纯粹的Virtual DOM。敲单词太累了,下文Virtual DOM一律用VD表示。
Dickensl
2022/06/14
7650
你不知道的Virtual DOM(三):Virtual Dom更新优化
[译] 认识虚拟 DOM
概括地说,文档对象模型(DOM)包含两部分;一是 HTML 文档基于对象的表示,二是操作该对象的一系列接口。影子 DOM 可以被认为是 DOM 的缩减版。它也是 HTML 元素基于对象的表示(推荐这篇神奇的Shadow DOM,能更好的理解影子 DOM),影子 DOM 能把 DOM 分离成更小封装位,并且能够跨 HTML 文档使用。
码农小余
2022/06/16
6980
[译] 认识虚拟 DOM
如何编写你自己的 Virtual DOM
为了构建你自己的 Virtual DOM,你只需要知道两件事,甚至你都不必深入 React 或者其它 Virtual DOM 实现的源码。因为它们都太庞大和复杂了 —— 但是实际上 Virtual DOM 的主要部分可以用少于 50 行代码实现。50 行!!!
疯狂的技术宅
2019/03/27
7640
如何编写你自己的 Virtual DOM
你不知道的Virtual DOM(二):Virtual Dom的更新
目前最流行的两大前端框架,React 和 Vue,都不约而同的借助 Virtual DOM 技术提高页面的渲染效率。那么,什么是 Virtual DOM ?它是通过什么方式去提升页面渲染效率的呢?本系列文章会详细讲解 Virtual DOM 的创建过程,并实现一个简单的 Diff 算法来更新页面。本文的内容脱离于任何的前端框架,只讲最纯粹的 Virtual DOM 。敲单词太累了,下文 Virtual DOM 一律用 VD 表示。
Dickens
2019/06/18
7250
推荐阅读
相关推荐
Vue 虚拟 DOM 的本质与引入原因详解及示例代码
更多 >
目录
  • Keep Moving
  • 神奇的虚拟DOM
    • 实现一下虚拟DOM
      • 创建虚拟DOM
      • 调用createElement方法
      • 渲染虚拟DOM
      • 调用render方法
  • DOM-diff闪亮登场
    • 比较规则
  • patch补丁更新
    • patch做了什么?
  • 回归
  • 四句话
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档