Vue3 KeepAlive实现原理解析

 更新时间:2022年09月05日 17:04:02   作者:Axin  
KeepAlive 是一个内置组件,那封装一个组件对于大家来说应该不会有太大的困难,它的核心逻辑在于它的 render 函数,它用 map 去记录要缓存的组件,就是 [key,vnode] 的形式,这篇文章主要介绍了Vue3 KeepAlive实现原理,需要的朋友可以参考下

思路

首先我们知道 KeepAlive 是一个内置组件,那封装一个组件对于大家来说应该不会有太大的困难,它的核心逻辑在于它的 render 函数,它用 map 去记录要缓存的组件,就是 [key,vnode] 的形式。它的核心思想就是 LRU,当我们限制有 maxSize 的时候,超过 maxSize 时我们会删除最久没有使用的[key, vnode],可以看看 leetcode146.LRU缓存;基本上你理清了 LRU 算法的思路,keepalive 的原理你也知道的差不多了。

代码解析

我只贴出来能帮助大家理解的核心代码,源码位于core/package/runtime-core/src/components/KeepAlive.ts

setup

const cache: Cache = new Map()
const keys: Keys = new Set()
// cache sub tree after render
let pendingCacheKey: CacheKey | null = null
const cacheSubtree = () => {
  // fix #1621, the pendingCacheKey could be 0
  if (pendingCacheKey != null) {
    cache.set(pendingCacheKey, getInnerChild(instance.subTree))
  }
}
// 组件挂载和更新的时候就会缓存最新的组件
onMounted(cacheSubtree)
onUpdated(cacheSubtree)

render

tips:这块逻辑就是 setup 的返回值

  const comp = vnode.type as ConcreteComponent
  const key = vnode.key == null ? comp : vnode.key
  pendingCacheKey = key
  const cachedVNode = cache.get(key)
  
  // tips: keys 仅仅是用于收集组件的 key 组件实际收集在cache中
  if (cachedVNode) { // 节点存在缓存中
    // copy over mounted state(复制过去的状态)
    vnode.el = cachedVNode.el
    vnode.component = cachedVNode.component

    // 将节点放到队尾
    keys.delete(key) 
    keys.add(key)
  } else { // 不存在
    keys.add(key) // 加入缓存队列
    // prune oldest entry
    // 超过最大值了,将最久没有使用的组件删除,也就是队头组件
    if (max && keys.size > parseInt(max as string, 10)) { 
      pruneCacheEntry(keys.values().next().value)
    }
  }

onActivated 和 onDeactived调用

tips:这两块逻辑是在 diff 中,看不懂没关系,只要注意一个点就是被缓存的组件节点有一个标识 ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE,我们在挂载组件的时候和卸载组件的时候判断一下是否有这个标识,有就去调用 onActiveated 或 onDeactived;源码位于:core/package/runtime-core/src/renderer

if (shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
  ;(parentComponent!.ctx as KeepAliveContext).deactivate(vnode)
  return
}

if (
  initialVNode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE ||
  (parent &&
    isAsyncWrapper(parent.vnode) &&
    parent.vnode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE)
) {
  instance.a && queuePostRenderEffect(instance.a, parentSuspense)
  if (
    __COMPAT__ &&
    isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
  ) {
    queuePostRenderEffect(
      () => instance.emit('hook:activated'),
      parentSuspense
    )
  }
}

到此这篇关于Vue3 KeepAlive实现原理的文章就介绍到这了,更多相关Vue3 KeepAlive原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • vue 父组件给子组件传值子组件给父组件传值的实例代码

    vue 父组件给子组件传值子组件给父组件传值的实例代码

    这篇文章主要介绍了vue 父组件给子组件传值,子组件给父组件传值,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-04-04
  • vue3给动态渲染的组件添加ref的解决方案

    vue3给动态渲染的组件添加ref的解决方案

    ref和reactive一样,也是用来实现响应式数据的方法,下面这篇文章主要给大家介绍了关于vue3给动态渲染的组件添加ref的解决方案,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-11-11
  • Vue3中如何使用异步请求示例详解

    Vue3中如何使用异步请求示例详解

    Vue3增加了很多让人眼前一亮的特征,suspense 组件就是其中之一,对处理异步请求数据非常实用,下面这篇文章主要给大家介绍了关于Vue3中如何使用异步请求的相关资料,需要的朋友可以参考下
    2022-06-06
  • 详解Vue中watch的详细用法

    详解Vue中watch的详细用法

    在vue中,使用watch来响应数据的变化。watch的用法大致有三种。下面代码是watch的一种简单的用法,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友参考下吧
    2018-11-11
  • 关于Vue虚拟dom问题

    关于Vue虚拟dom问题

    这篇文章主要介绍了Python合成Excel表的实现代码(多sheet),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • vue组件中实现嵌套子组件案例

    vue组件中实现嵌套子组件案例

    这篇文章主要介绍了vue组件中实现嵌套子组件案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • Vue实现图片轮播组件思路及实例解析

    Vue实现图片轮播组件思路及实例解析

    这篇文章主要介绍了Vue实现图片轮播组件思路及实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • 基于vue-cli3多页面开发apicloud应用的教程详解

    基于vue-cli3多页面开发apicloud应用的教程详解

    这篇文章主要介绍了基于vue-cli3多页面开发apicloud应用,本文采用vue-cli+APIcloud的方式写解决以上痛点,开发灵活,并且打包之后体积更小速度更快,需要的朋友可以参考下
    2019-06-06
  • vue 解决IOS10低版本白屏的问题

    vue 解决IOS10低版本白屏的问题

    这篇文章主要介绍了vue 解决IOS10低版本白屏的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • vue组件props属性监听不到值变化问题

    vue组件props属性监听不到值变化问题

    这篇文章主要介绍了vue组件props属性监听不到值变化问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04

最新评论