2025年3月31日 星期一 乙巳(蛇)年 正月初一 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > 数据结构与算法

虚拟 dom 和 diff 算法

时间:12-14来源:作者:点击数:12

什么是虚拟 dom?

所谓虚拟 dom 就是用一个 js 对象来描述一个 dom 节点

  • <div class="a">我是内容</div>
  • {
  • tag:'div', // 元素标签
  • attrs:{ // 属性
  • class:'a',
  • id:'b'
  • },
  • text:'我是内容', // 文本内容
  • children:[] // 子元素
  • }

为什么要有虚拟 dom?

因为浏览器把真实 dom 设计的很复杂,即使是一个空的 div 也有很多东西,这也导致了操作 dom 非常的消耗性能,使用虚拟 dom 的目的就是优化性能(用 js 的计算性能换取操作 dom 的性能),尽可能的避免 dom 操作。通过 diff 算法对比前后虚拟 dom,把需要改变的地方改变。

  • // vue的源码中有一个VNode类用来实例化各种虚拟dom
  • // 源码位置:src/core/vdom/vnode.js
  • export default class VNode {
  • constructor (
  • tag?: string,
  • data?: VNodeData,
  • children?: ?Array<VNode>,
  • text?: string,
  • elm?: Node,
  • context?: Component,
  • componentOptions?: VNodeComponentOptions,
  • asyncFactory?: Function
  • ) {
  • this.tag = tag /*当前节点的标签名*/
  • this.data = data /*当前节点对应的对象,包含了具体的一些数据信息,是一个VNodeData类型,可以参考VNodeData类型中的数据信息*/
  • this.children = children /*当前节点的子节点,是一个数组*/
  • this.text = text /*当前节点的文本*/
  • this.elm = elm /*当前虚拟节点对应的真实dom节点*/
  • this.ns = undefined /*当前节点的名字空间*/
  • this.context = context /*当前组件节点对应的Vue实例*/
  • this.fnContext = undefined /*函数式组件对应的Vue实例*/
  • this.fnOptions = undefined
  • this.fnScopeId = undefined
  • this.key = data && data.key /*节点的key属性,被当作节点的标志,用以优化*/
  • this.componentOptions = componentOptions /*组件的option选项*/
  • this.componentInstance = undefined /*当前节点对应的组件的实例*/
  • this.parent = undefined /*当前节点的父节点*/
  • this.raw = false /*简而言之就是是否为原生HTML或只是普通文本,innerHTML的时候为true,textContent的时候为false*/
  • this.isStatic = false /*静态节点标志*/
  • this.isRootInsert = true /*是否作为跟节点插入*/
  • this.isComment = false /*是否为注释节点*/
  • this.isCloned = false /*是否为克隆节点*/
  • this.isOnce = false /*是否有v-once指令*/
  • this.asyncFactory = asyncFactory
  • this.asyncMeta = undefined
  • this.isAsyncPlaceholder = false
  • }
  • get child (): Component | void {
  • return this.componentInstance
  • }
  • }

通过源代码可以清晰的看出,VNode 可以有多种类型:

  1. 注释节点
  2. 文本节点
  3. 元素节点
  4. 组件节点
  5. 函数式组件节点
  6. 克隆节点

在视图渲染之前,把写好的 template 模板先编译成 VNode 并缓存下来,等到数据发生变化页面需要重新渲染的时候,我们把数据发生变化后生成的 VNode 与前一次缓存下来的 VNode 进行对比,找出差异,然后有差异的 VNode 对应的真实 DOM 节点就是需要重新渲染的节点,最后根据有差异的 VNode 创建出真实的 DOM 节点再插入到视图中,最终完成一次视图更新。

diff 算法

打 patch 补丁,以新的 VNode 为基准,改造旧的 oldVNode 使之成为跟新的VNode一样,这就是 patch 过程要干的事。

通俗的来说就是之前的视图有一个虚拟 dom,当数据改变会生成新的虚拟 dom,新的虚拟 dom 会与之前的作比较,然后根据比较的结果做增删改,也就是在原来的基础上做改变。(优化主要体现在子节点上,包括到 vue3.0 的改变也主要是体现在子节点上)

流程图如下:

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐