vue源码学习 深入patch diff双端对比算法

Vue组件在beforeMount和mounted之间执行render生成新VNode,通过vm._update触发patch过程。在src/core/vdom/patch.js的patchVnode和updateChildren中,核心的diff算法用于比较并更新新旧子节点,实现高效DOM更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么时候调用patch

在beforeMount和mounted之间,会执行options.render函数生成新的VNode树。然后调用vm._update(新VNode)更新,然后进入到patch阶段。

// src/core/instance/lifecycle.js

export function mountComponent (
  vm: Component,
  el: ?Element,
  hydrating?: boolean
): Component {
   
  callHook(vm, 'beforeMount')
  let updateComponent = () => {
   
    vm._update(vm._render(), hydrating)
  }
  vm._watcher = new Watcher(vm, updateComponent, noop)
  hydrating = false //默认不是ssr渲染
  callHook(vm, 'mounted')
}
Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {
   
 const vm: Component = this
  if (vm._isMounted) {
   
    callHook(vm, 'beforeUpdate')
  }
  const prevEl = vm.$el
  const prevVnode = vm._vnode
  const prevActiveInstance = activeInstance
  activeInstance = vm
  vm._vnode = vnode
  if (!prevVnode) {
   
    // 旧虚拟节点不存在,第一次渲染,hydrating=false表示不是ssr
    vm.$el = vm.__patch__(
      vm.$el, vnode, hydrating, false /* removeOnly */,
      vm.$options._parentElm,
      vm.$options._refElm
    )
    vm.$options._parentElm = vm.$options._refElm = null
  } else {
   
    // 不是第一次渲染, patch对比新旧虚拟dom树
    vm.$el = vm.__patch__(prevVnode, vnode)
  }
  activeInstance = prevActiveInstance
  // update __vue__ reference
  if (prevEl) {
   
    prevEl.__vue__ = null
  }
  if (vm.$el) {
   
    vm.$el.__vue__ = vm
  }
  // if parent is an HOC, update its $el as well
  if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
   
    vm.$parent.$el = vm.$el
  }
}

在src/core/vdom/patch.js中

从createPatchFunction() => patch() =>patchVnode() => updateChildren()。
updateChildren()里面就是diff双端对比算法了

// vue2 使用双端比较算法,借鉴于开源项目:snabbdom,但最早采用双端比较算法的库是 citojs
return function patch (oldVnode, vnode, hydrating, removeOnly, parentElm, refElm) {
   
  if (isUndef(vnode)) {
    // 不存在新节点则直接销毁旧节点
    if (isDef(oldVnode)) invokeDestroyHook(oldVnode)
    return
  }

  let isInitialPatch = false
  const insertedVnodeQueue = []

  if (isUndef(oldVnode)) {
    // 第一次挂载不存在旧节点,直接渲染新节点
    isInitialPatch = true
    createElm(vnode, insertedVnodeQueue, parentElm, refElm)
  } else {
   
    const isRealElement = isDef(oldVnode.nodeType)
    if (!isRealElem
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值