当前位置:首页 > VUE

vue diff实现

2026-02-10 06:38:31VUE

Vue 的 Diff 算法实现

Vue 的虚拟 DOM Diff 算法(即 patch 过程)通过高效比较新旧虚拟节点(VNode)来最小化 DOM 操作。其核心逻辑基于 同层比较双端比较 策略,以下是关键实现要点:

核心流程

同层比较
Diff 只在同一层级的 VNode 间进行,跨层级移动节点会直接销毁并重建,避免递归遍历带来的性能损耗。

双端比较
通过四个指针(新旧节点的头尾索引)逐步向中间靠拢,优先处理以下四种简单情况:

  1. 旧头 vs 新头
  2. 旧尾 vs 新尾
  3. 旧头 vs 新尾
  4. 旧尾 vs 新头

若均不匹配,则通过 key 查找可复用的节点。

vue diff实现

关键代码逻辑

1. 节点复用条件
判断两个 VNode 是否可复用:

function sameVnode(a, b) {
  return (
    a.key === b.key && // key 相同
    a.tag === b.tag && // 标签类型相同
    a.isComment === b.isComment && // 注释节点相同
    isDef(a.data) === isDef(b.data) && // 数据属性存在性一致
    sameInputType(a, b) // 输入类型相同(针对 input 元素)
  )
}

2. 双端比较实现
以下是简化后的核心逻辑:

vue diff实现

while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
  if (isUndef(oldStartVnode)) {
    oldStartVnode = oldCh[++oldStartIdx]
  } 
  else if (isUndef(oldEndVnode)) {
    oldEndVnode = oldCh[--oldEndIdx]
  }
  // 情况1:旧头 == 新头
  else if (sameVnode(oldStartVnode, newStartVnode)) {
    patchVnode(oldStartVnode, newStartVnode)
    oldStartVnode = oldCh[++oldStartIdx]
    newStartVnode = newCh[++newStartIdx]
  }
  // 情况2:旧尾 == 新尾
  else if (sameVnode(oldEndVnode, newEndVnode)) {
    patchVnode(oldEndVnode, newEndVnode)
    oldEndVnode = oldCh[--oldEndIdx]
    newEndVnode = newCh[--newEndIdx]
  }
  // 情况3:旧头 == 新尾(节点右移)
  else if (sameVnode(oldStartVnode, newEndVnode)) {
    patchVnode(oldStartVnode, newEndVnode)
    insertBefore(parentElm, oldStartVnode.elm, nextSibling(oldEndVnode.elm))
    oldStartVnode = oldCh[++oldStartIdx]
    newEndVnode = newCh[--newEndIdx]
  }
  // 情况4:旧尾 == 新头(节点左移)
  else if (sameVnode(oldEndVnode, newStartVnode)) {
    patchVnode(oldEndVnode, newStartVnode)
    insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm)
    oldEndVnode = oldCh[--oldEndIdx]
    newStartVnode = newCh[++newStartIdx]
  }
  // 情况5:通过 key 查找可复用节点
  else {
    const idxInOld = findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
    if (isUndef(idxInOld)) {
      createElm(newStartVnode, parentElm, oldStartVnode.elm)
    } 
    else {
      const vnodeToMove = oldCh[idxInOld]
      patchVnode(vnodeToMove, newStartVnode)
      insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm)
      oldCh[idxInOld] = undefined
    }
    newStartVnode = newCh[++newStartIdx]
  }
}

3. 剩余节点处理
循环结束后,若新旧节点列表有剩余:

  • 新列表有剩余:批量新增节点
  • 旧列表有剩余:批量删除节点

优化策略

key 的作用
key 是节点复用的关键标识。若未设置 key,Vue 会默认按位置复用,可能导致状态错乱或性能下降。

静态节点标记
编译阶段标记静态节点(isStatic),Diff 时直接跳过比较,提升性能。

复杂度分析

  • 最优情况:头尾匹配时达到 O(n) 复杂度。
  • 最差情况:无 key 或乱序时退化为 O(n²),但实际场景中通过 key 优化可避免。

通过这种策略,Vue 在大多数实际应用中能高效更新 DOM,减少不必要的渲染开销。

标签: vuediff
分享给朋友:

相关文章

vue实现图片分析

vue实现图片分析

Vue 实现图片分析的方法 在 Vue 中实现图片分析通常涉及图片上传、预览、后端交互以及分析结果展示等功能。以下是几种常见的实现方式: 使用 HTML5 File API 和 Canvas…

vue登录逻辑的实现

vue登录逻辑的实现

Vue 登录逻辑实现 前端实现 创建登录组件 在 Vue 项目中创建一个登录组件,通常命名为 Login.vue。该组件包含表单元素,如用户名和密码输入框,以及提交按钮。 <template&…

vue设计与实现 书

vue设计与实现 书

vue设计与实现 书 《Vue.js设计与实现》是一本深入探讨Vue.js框架内部原理和设计思想的书籍,适合希望深入理解Vue.js的开发者。以下是关于这本书的详细信息: 书籍内容 《Vue…

vue实现单点

vue实现单点

Vue 实现单点登录(SSO)方案 单点登录(SSO)允许用户在多个相关但独立的系统中使用同一组凭证登录。以下是基于 Vue 的实现方案: 基于 OAuth2/OpenID Connect 的实现…

vue实现付款

vue实现付款

Vue 实现付款功能 在 Vue 中实现付款功能通常需要集成第三方支付网关(如支付宝、微信支付、Stripe 等)。以下是常见的实现方法: 集成支付宝/微信支付 安装必要的依赖(如 axios 用…

vue分类实现

vue分类实现

Vue分类实现方法 在Vue中实现分类功能通常涉及数据分组、动态渲染和交互逻辑。以下是几种常见的实现方式: 基于计算属性的分类 通过计算属性对原始数据进行分组处理,适合静态或少量数据分类: c…