Vue源码-keep-alive

本文详细介绍了Vue中Keep-Alive组件的工作原理与实现机制,包括如何通过缓存已创建的VNode来提高组件的复用效率,以及组件生命周期内的缓存管理和更新策略。

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

<keep-alive> 是Vue中实现的一个组件。
文件源码:src/core/components/keep-alive.js

export default {
  name: 'keep-alive,
  abstract: true, // initLifecycle中

  props: {
    include: patternTypes, // 只有匹配的才会被缓存
    exclude: patternTypes, // 任何匹配的都不会缓存
    max: [String, Number] // 指定缓存大小
  },

  created () {
    // 缓存已经创建过的VNode
    this.cache = Object.create(null)
    this.keys = []
  },

  destroyed () {
    for (const key in this.cache) {
      pruneCacheEntry(this.cache, key, this.keys)
    }
  },

  mounted () {
    this.$watch('include', val => {
      pruneCache(this, name => matches(val, name))
    })
    this.$watch('exclude', val => {
      pruneCache(this, name => !matches(val, name))
    })
  },

  render () {
    const slot = this.$slots.default // 获取默认插槽
    const vnode: VNode = getFirstComponentChild(slot) // 获取第一个子节点
    const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
    if (componentOptions) {
      // check pattern
      const name: ?string = getComponentName(componentOptions)
      const { include, exclude } = this
      if (
        // not included
        (include && (!name || !matches(include, name))) ||
        // excluded
        (exclude && name && matches(exclude, name))
      ) {
        return vnode
      }

      const { cache, keys } = this
      const key: ?string = vnode.key == null
        // same constructor may get registered as different local components
        // so cid alone is not enough (#3269)
        ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
        : vnode.key
	  // 如果命中缓存,则直接从缓存中拿VNode的组件实例,并将key放到最后一个
      if (cache[key]) {
        vnode.componentInstance = cache[key].componentInstance
        // make current key freshest
        remove(keys, key)
        keys.push(key)
      } else {
        cache[key] = vnode
        keys.push(key)
        // prune oldest entry
        // 如果配置了max并且缓存长度超过this.max,从缓存中删除第一个
        if (this.max && keys.length > parseInt(this.max)) {
          pruneCacheEntry(cache, keys[0], keys, this._vnode)
        }
      }

      vnode.data.keepAlive = true
    }
    return vnode || (slot && slot[0])
  }
}
// 针对数组、字符串、正则分别匹配
function matches (pattern: string | RegExp | Array<string>, name: string): boolean {
  if (Array.isArray(pattern)) {
    return pattern.indexOf(name) > -1
  } else if (typeof pattern === 'string') {
    return pattern.split(',').indexOf(name) > -1
  } else if (isRegExp(pattern)) {
    return pattern.test(name)
  }
  /* istanbul ignore next */
  return false
}
watch: {
  include (val: string | RegExp | Array<string>) {
    pruneCache(this, name => matches(val, name))
  },
  exclude (val: string | RegExp | Array<string>) {
    pruneCache(this, name => !matches(val, name))
  }
}

function pruneCache (keepAliveInstance: any, filter: Function) {
  const { cache, keys, _vnode } = keepAliveInstance
  for (const key in cache) {
    const cachedNode: ?VNode = cache[key]
    if (cachedNode) {
      const name: ?string = getComponentName(cachedNode.componentOptions)
      if (name && !filter(name)) {
        pruneCacheEntry(cache, key, keys, _vnode)
      }
    }
  }
}

对cache做遍历,发现缓存的节点名称和新的规则没有匹配上的时候,把这个缓存节点从缓存中摘除。

在渲染过程中,patch之前会进行diff,会先执行prepatch钩子函数,<keep-alive>组件在执行prepatch时,需要对自己的slots重新解析。并触发<keep-alive>组件实例 $forceUpdate 逻辑,也就是重新执行 <keep-alive> 的 render 方法,这个时候如果它包裹的第一个组件 vnode 命中缓存,则直接返回缓存中的 vnode.componentInstance,接着又会执行 patch 过程,再次执行到 createComponent 方法。
在执行 init 钩子函数的时候不会再执行组件的 mount 过程了,被 <keep-alive> 包裹的组件在有缓存的时候不会再执行组件的 created、mounted 等钩子函数

Vuekeep-alive 组件是用来缓存具有相同组件名称的组件的,例如在一个 Tab 页中不同的 Tab 相互切换时,当前 Tab 中的组件及其状态可以被 keep-alive 缓存,以避免在该 Tab 内重复加载组件和数据。 源码中实现了两个生命周期方法 activate() 和 deactivate() 来控制缓存中的组件的挂载和卸载。缓存中的组件通过 mount() 方法来挂载,并在 activated 钩子函数中调用 vnode 的 activated 钩子函数和组件的 activated 钩子函数。 当组件被激活(activated)时,keep-alive 会调用 activate() 方法,该方法会检查被缓存组件的缓存状态,并通过缓存对象的 updated 标志来决定组件是否需要重新挂载。如果需要重新挂载,则通过缓存对象的 vnode 函数重新渲染组件,并调用新组件的 mounted 和 activated 钩子函数。 当组件被停用(deactivated)时,keep-alive 会调用 deactivate() 方法,该方法会调用被缓存组件的 deactivated 钩子函数,并通过 VNode 的 tag 属性判断组件是否需要被销毁。如果不需要被销毁,则缓存对象会记录其销毁状态并保留其状态,下次使用时可以快速还原组件。如果需要被销毁,则通过调用缓存对象的 destroy() 方法来销毁组件并释放资源。 总之,Vue keep-alive 组件通过缓存组件的方式来提高应用程序的性能和用户体验,实现了快速切换和缓存组件的功能。它的核心在于更新缓存中的组件,并且在组件被激活和停用时触发生命周期函数来维护组件的状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值