最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 虚拟 DOM 和 DOM diff

    正文概述 掘金(LeahDizon)   2021-02-22   549

    虚拟 DOM 是什么

    在操作真实 DOM 的过程中,JavaScript 的执行时间是很快的,但是浏览器在渲染页面的时候,会让页面不可交互。虚拟 DOM 是一个和真实 DOM 对应的概念。它是对 DOM 的抽象,本质上是 JavaScript 对象,这个对象就是更加轻量级的对 DOM 的描述,优化 DOM 的操作。

    真实 DOM:

    <div class="red">
        <span></span>
        <span></span>
    </div>
    

    虚拟 DOM (React):

    const vNode = {
        key: null,
        type: "div", // 标签名或组件名
        props: {
            children: [ // 子元素节点
                {type: 'span', ...},
                {type: 'span', ...}
            ],
            className: "red", // 标签上的属性
            onClick: () => {} // 事件
        },
        ref: null,
        ...
    }
    

    虚拟 DOM (Vue):

    const vNode = {
        tag: "div", // 标签名或组件名
        data: {
            class: "red", // 标签上的属性
            on: {
                click: () => {} // 事件
            }
        },
        children: [ // 子元素节点
            {tag: "span", ...},
            {tag: "span", ...}
        ],
        ...
    }
    

    如何创建虚拟 DOM

    • React.createElement
    createElement('div', {className:'red', onClick: () => {}}, [
        createElement('span', {}, 'span1'),
        createElement('span', {}, 'span2')
      ]
    )
    
    • Vue(只能在 render 函数里得到 h)
    h('div', {
        class: 'red',
        on: {
            click: () => {}
        },
    }, [h('span', {}, 'span1'), h('span', {}, 'span2')])
    

    简化创建虚拟 DOM

    • React JSX:
    <div className="red" onClick={fn}>
        <span>span1</span>
        <span>span2</span>
    </div>
    

    这种写法很像真实 DOM,但是不是真实 DOM。因为真实 DOM 没有 classNameonClick 这种写法,标签里不写 {}

    通过 babel 转为 createElement 形式

    • Vue Template:
    <div class="red" @click="fn">
        <span>span1</span>
        <span>span2</span>
    </div>
    

    通过 vue-loader 转为 h 形式

    虚拟 DOM 的优点

    1. 减少 DOM 操作

    虚拟 DOM 可以将多次操作合并为一次操作,比如我们添加 1000 个节点,真实 DOM 操作却是一个接一个操作的。

    虚拟 DOM 借助 DOM diff 可以把多余的操作省掉,比如我们添加 1000 个节点,其实只有 10 个是新增的。

    1. 跨平台

    虚拟 DOM 不仅可以变成 DOM,还可以变成小程序、iOS 应用、安卓应用,因为虚拟 DOM 本质上是一个 JavaScript 对象。这也就是虚拟 DOM 最初的目的。比如 Node.js 就没有 DOM,如果想实现 SSR (服务端渲染),那么一个方式就是借助虚拟 DOM。

    虚拟 DOM 的缺点

    需要额外的创建函数,例如 createElementh ,但可以通过 JSX 来简化成 XML 写法,但是这种写法严重依赖打包工具,要添加额外的构建过程。

    DOM diff 是什么

    DOM diff 是虚拟 DOM 的对比算法,是用来对比差异的算法。

    我们将虚拟 DOM 想象成树形

    <div :class="x">
        <span v-if="y">{span1}</span>
        <span>{span2}</span>
    </div>
    

    这段代码我们会得到一颗虚拟 DOM 树:

    虚拟 DOM 和 DOM diff

    当数据变化时:

    • x 从 red 变成 green

    虚拟 DOM 和 DOM diff 虚拟 DOM 和 DOM diff

    • DOM diff 发现

    div 标签类型没变,只需要更新 div 对应的 DOM 的属性

    子元素没变,不更新

    • y 从 true 变成 false

    虚拟 DOM 和 DOM diff 虚拟 DOM 和 DOM diff

    • DOM diff 发现

    div 没变,不用更新

    子元素1标签没变,但是 children 变了,更新了 DOM 内容

    子元素2不见,删除对应的 DOM

    总结:DOM diff 就是一个函数,我们称之为 patch 。其用法为 patches = patch(oldVNode, newVNode),patches 就是要运行的 DOM 操作。由于 Vue 和 React diff 算法是不一致的,它们的操作是不一致的,但是主体特征是不会变的,都是需要给两个虚拟 DOM 节点,得到对应的 DOM 操作,这个操作不会立即执行,而是等全部的虚拟 DOM 节点更新完了,再一次性把这些 DOM 操作依次执行。

    我们已经知道了 DOM diif 的结构,现在我们来了解一下 DOM diff 的大概逻辑。

    Tree diff

    • 将新旧两棵树逐层对比,找出哪些节点需要更新
    • 如果节点是组件,就看 Component diff
    • 如果节点是标签,就看 Element diff

    Component diff

    如果节点是组件,就先看组件类型,类型不同直接替换(删除旧的);类型相同则只更新属性,然后深入组件做 Tree diff(递归)。

    Element diff

    如果节点是原生标签,则看标签名。标签名不同直接替换,相同则只更新属性,然后进入标签后代做 Tree diff (递归)。

    通过以上分析,DOM diff 对树的逐层对比,实现了减少 DOM 操作的次数。

    DOM diff 的问题

    如上 span 节点的删除图例,DOM diff 要做的更新操作是,检查第一个 span 的内容 hello 变为 world ,然后检查第二个 span 被删除,于是要做一个更新和一个删除的操作。而不是直接删除第一个 span ,将第二个 span 左移的过程。

    那么这里就出现了问题,我们来看下一个例子:

    通过这个在线例子 点击查看 ,我们可以看出如下问题

    虚拟 DOM 和 DOM diff

    点击第二个删除之后:

    虚拟 DOM 和 DOM diff

    我们删除了数组的 2,得到长度为 2 的新数组,2 更新为 3,但是内容 不变。那么为什么会出现这个问题。

    计算机认为我们把 2 变成了 3,然后删除了 3

    首先,计算机通过遍历进行比对,对比 1 和 1 ,发现 "1 没变" 。然后对比 2 和 3 ,发现 "2 变成了 3" 。最后对比 undefined 和 3 ,发现 "3 被删除了" 。

    所以就得到了这个结果。

    虚拟 DOM 和 DOM diff

    解决方法也很简单,我们只需要配置一个唯一值作为 key 就可以了,让计算机根据这个 key ,知道我们操作的是哪个 DOM ,这样计算机就可以直接删除 2 了。


    起源地下载网 » 虚拟 DOM 和 DOM diff

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元