虚拟DOM和DOM diff

虚拟DOM是一种优化DOM操作的技术,通过创建JS对象来代表DOM树,减少实际DOM操作,提升性能。它能跨平台,适用于多种环境。虚拟DOM通过DOMdiff算法比较新旧状态,找到最小变更,生成最小更新操作集。本文还介绍了React和Vue中创建虚拟DOM的方法,以及JSX简化代码的方式。然而,虚拟DOM也存在额外的创建成本和依赖于打包工具的缺点。为了优化,我们需要合理设置节点的key属性。
摘要由CSDN通过智能技术生成

虚拟DOM优点

减少DOM操作

  • 虚拟 DOM 可以将多次操作合并为一次操作,比如你添加 1000 个节点,却是一个接一个操作的(减少频率)
  • 虚拟 DOM 借助 DOM diff 可以把多余的操作省掉,比如你添加 1000 个节点,其实只有 10 个是新增的(减少范围)

跨平台

  • 虚拟 DOM 不仅可以变成 DOM,还可以变成小程序、iOS 应用、安卓应用,因为虚拟 DOM 本质上是一个 JS 对象

React虚拟DOM

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

Vue虚拟DOM

// Vue
const vNode = {
  tag: "div", // 标签名 or 组件名
  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'])

使用JSX简化

// React JSX
<div className="red" onClick="{()=> {}}">
    <span>span1</span>
    <span>span2</span>
</div>
// Vue Template
h('div', {
  class: 'red',
  on: {
    click: () => { }
  },
}, [h('span',{},'span1'), h('span', {}, 'span2'])
// React
<div className="red" onClick={fn}>
    <span>span1</span>
    <span>span2</span>
</div>
// 通过 babel 转为 createElement 形式
// Vue Template
<div class="red" @click="fn">
  <span>span1</span>
  <span>span2</span>
</div>
// 通过 vue-loader 转为 h 形式
// 现在创建虚拟 DOM 的方法
// React
<div className="red" onClick={fn}>
    <span>span1</span>
    <span>span2</span>
</div>
// 通过 babel 转为 createElement 形式
// Vue Template
<div class="red" @click="fn">
  <span>span1</span>
  <span>span2</span>
</div>
// 通过 vue-loader 转为 h 形式

总结

虚拟 DOM 是什么

  • 虚拟dom的本质一个能代表dom树的JS对象,包含tag、props、children三个属性
  • 通常含有标签名、标签上的属性、事件监听和子元素们,以及其他属性

虚拟 DOM 有什么缺点

  • 需要额外的创建函数,如 createElement 或 h,但可以通过 JSX 来简化成 XML 写法,会依赖打包工具。

DOM diff

/* 
 什么是 DOM diff
 就是一个函数,我们称之为 patch
 patches = patch(oldVNode, newVNode)
 patches 就是要运行的 DOM 操作,可能长这样:
*/
[
  {type: 'INSERT', vNode: ... },
  {type: 'TEXT',  vNode: ... },
  {type: 'PROPS', propsPatch: [...]}
]

Tree diff

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

Component diff

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

Element diff

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

存在一些小小的问题

DOM diff在同层级对比中有bug。造成页面渲染错误。
同一层级的一组节点可以通过唯一的id进行区分, 所以可以给节点设定唯一的key。
从而消除bug。key只能是number和string类型,一定不要用index作为key值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Supernova_gu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值