我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Vue中的KeepAlive组件怎么使用

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Vue中的KeepAlive组件怎么使用

这篇文章主要介绍“Vue中的KeepAlive组件怎么使用”,在日常操作中,相信很多人在Vue中的KeepAlive组件怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue中的KeepAlive组件怎么使用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

KeepAlive 是什么

<KeepAlive> 是一个内置组件,它的功能是在多个组件间动态切换缓存被移除的组件实例。

KeepAlive 功能

KeepAlive 一词借鉴于 HTTP 协议,在 HTTP 协议里面 KeepAlive 又称持久连接,作用是允许多个请求/响应共用同一个 HTTP 连接,解决了频繁的销毁和创建 HTTP 连接带来的额外性能开销。而同理 Vue 里的 KeepAlive 组件也是为了避免一个组件被频繁的销毁/重建,避免了性能上的开销。

// App.vue<Test :msg="curTab" v-if="curTab === 'Test'"></Test><HelloWorld :msg="curTab" v-if="curTab === 'HelloWorld'"></HelloWorld><div @click="toggle">toggle</div>

上述代码可以看到,如果我们频繁点击 toggle 时会频繁的渲染 Test/HelloWorld 组件,当用户频繁的点击时 Test 组件需要频繁的销毁/渲染,这就造成很大的渲染性能损失。

所以为了解决这种性能开销,你需要知道是时候使用 KeepAlive 组件。

<KeepAlive>  <component :is="curTab === 'Test' ? Test : HelloWorld" :msg="curTab"></component></KeepAlive><div @click="toggle">toggle</div>

Vue中的KeepAlive组件怎么使用

可以看这个录屏,在首次加载后再次频繁的切换并没有重新销毁与挂载,而仅仅是将组件进行了失活(而不是销毁),渲染时只需要重新激活就可以,而不需重新挂载,如果要渲染的组件很大,那就能有不错的性能优化。

想要体验的话可以去看看这个例子?官方demo,其中数据会被缓存这个也需要在开发使用中去注意到的

如何实现

实现原理其实很简单,其实就是缓存管理和特定的销毁和渲染逻辑,使得它不同于其他组件。

KeepAlive 组件在卸载组件时并不能真的将其卸载,而是将其放到一个隐藏的容器里面当被激活时再从隐藏的容器中拿出来挂载到真正的 dom 上就行,这也就对应了 KeepAlive 的两个独特的生命周期activateddeactivated

Vue中的KeepAlive组件怎么使用

先来简单了解下组件的挂载过程

Vue中的KeepAlive组件怎么使用

所以在 KeepAlive 内的子组件在 mount 和 unmount 的时候会执行特定的渲染逻辑,从而不会去走挂载和销毁逻辑

具体实现(实现一个小而简单的 KeepAlive)

  • KeepAlive 组件的属性

const KeepAliveImpl: ComponentOptions = {  name: "KeepAlive",  // 标识这是一个 KeepAlive 组件  __isKeepAlive: true,  // props  props: {    exclude: [String, Array, RegExp],    include: [String, Array, RegExp],    max: [String, Number]  } }  // isKeepAlive export const isKeepAlive = (vnode: VNode): boolean =>  (vnode.type as any).__isKeepAlive

  • KeepAlive 组件的 setup 逻辑以及渲染逻辑(重点看)

// setup 接着上面的代码// 获取到当前 KeepAlive 组件实例const instance = getCurrentInstance()! as any;// 拿到 ctxconst sharedContext = instance.ctx as KeepAliveContext;// cache 缓存// key: vnode.key | vnode.type value: vnodeconst cache: Cache = new Map()// 需要拿到某些的 renderer 操作函数,需要自己特定执行渲染和卸载逻辑const { renderer: { p: patch, m: move, um: _unmount, o: { createElement } } } = sharedContext// 隐藏的容器,用来存储需要隐藏的 domconst storeageContainer = createElement('div')// 存储当前的子组件的缓存 keylet pendingKey: CacheKey | null = nullsharedContext.activate = (vnode, container, anchor) => {  // KeepAlive 下组件激活时执行的 move 逻辑  move(vnode, container, anchor, 0 )}sharedContext.deactivate = (vnode) => {  // KeepAlive 下组件失活时执行的 move 逻辑  move(vnode, storeageContainer, null, 1 )}return () => {  // 没有子组件  if (!slots.default) {    return null;  }  const children = slots.default() as VNode[];  const rawNode = children[0];  let vnode = rawNode;  const comp = vnode.type as ConcreteComponent;  const name = comp.displayName || comp.name  const { include, exclude } = props;  // 没有命中的情况  if (    (include && (!name || !matches(include, name))) ||    (exclude && name && matches(exclude, name))  ) {    // 直接渲染子组件    return rawNode;  }  // 获取子组件的 vnode key  const key = vnode.key == null ? comp : vnode.key;  // 获取子组件缓存的 vnode  const cachedVNode = cache.get(key);  pendingKey = key;  // 命中缓存  if (cachedVNode) {    vnode.el = cachedVNode.el;    // 继承组件实例    vnode.component = cachedVNode.component;    // 在 vnode 上更新 shapeFlag,标记为 COMPONENT_KEPT_ALIVE 属性,防止渲染器重新挂载    vnode.shapeFlag |= ShapeFlags.COMPONENT_KEPT_ALIVE  } else {    // 没命中将其缓存    cache.set(pendingKey, vnode)  }  // 在 vnode 上更新 shapeFlag,标记为 COMPONENT_SHOULD_KEEP_ALIVE 属性,防止渲染器将组件卸载了  vnode.shapeFlag |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE  // 渲染组件 vnode  return vnode;}

  • KeepAlive组件 mount 时挂载 renderer 到 ctx 上

在 KeepAlive 组件内会从 sharedContext 上的 renderer 上拿到一些方法比如 move、createElement 等

function mountComponent() { // ... if (isKeepAlive(initialVNode)) {    ;(instance.ctx as KeepAliveContext).renderer = internals  }}

  • 子组件执行特定的销毁和渲染逻辑

首先从上面可以看到,在渲染 KeepAlive 组件时会对其子组件的 vnode 上增加对应的 shapeFlag 标志

比如COMPONENT_KEPT_ALIVE标志,组件挂载的时候告诉渲染器这个不需要 mount 而需要特殊处理

const processComponent = (    n1: VNode | null,    n2: VNode,    container: RendererElement,    anchor: RendererNode | null,  ) => {    if (n1 == null) {      // 在 KeepAlive 组件渲染时会对子组件增加 COMPONENT_KEPT_ALIVE 标志      // 挂载子组件时会判断是否 COMPONENT_KEPT_ALIVE ,如果是不会调用 mountComponent 而是直接执行 activate 方法      if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) {        ;(parentComponent!.ctx as KeepAliveContext).activate(          n2,          container,          anchor        )      }      // ...    }  }

同理COMPONENT_SHOULD_KEEP_ALIVE标志也是用来在组件卸载的时候告诉渲染器这个不需要 unmount 而需要特殊处理。

const unmount: UnmountFn = (vnode) => {  // ...  // 在 KeepAlive 组件渲染时会对子组件增加 COMPONENT_SHOULD_KEEP_ALIVE 标志  // 然后在子组件卸载时并不会真实的卸载而是调用 KeepAlive 的 deactivate 方法  if (shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {    ;(parentComponent!.ctx as KeepAliveContext).deactivate(vnode)    return  }}

  • 如何挂载activateddeactivated生命周期(生命周期相关可以不用重点看)

首先这两个生命周期是在 KeepAlive 组件内独特声明的,是直接导出使用的。

export function onActivated(  hook: Function,  target?: ComponentInternalInstance | null) {  // 注册 activated 的回调函数到当前的 instance 的钩子函数上  registerKeepAliveHook(hook, LifecycleHooks.ACTIVATED, target)}export function onDeactivated(  hook: Function,  target?: ComponentInternalInstance | null) {  // 注册 deactivated 的回调函数到当前的 instance 的钩子函数上  registerKeepAliveHook(hook, LifecycleHooks.DEACTIVATED, target)}

然后因为这两个生命周期会注册在 setup 里面,所以只要执行 setup 就会将两个生命周期的回调函数注册到当前的 instance 实例上

// renderer.ts// mount 函数逻辑const mountComponent = (initialVNode,  container,  anchor,  parentComponent,  parentSuspense,  isSVG,  optimized) => {  // ...  const instance: ComponentInternalInstance =    compatMountInstance ||    (initialVNode.component = createComponentInstance(    initialVNode,    parentComponent,    parentSuspense  ))  // 执行 setup  setupComponent(instance)}// setupcomponent 处理 setup 函数值export function setupComponent(  instance: ComponentInternalInstance,  isSSR = false) {  // ...  const isStateful = isStatefulComponent(instance)  // ...  const setupResult = isStateful    // setupStatefulComponent 函数主要功能是设置当前的 instance    ? setupStatefulComponent(instance, isSSR)    : undefined  // ...}function setupStatefulComponent(  instance: ComponentInternalInstance){  if (setup) {    //设置当前实例    setCurrentInstance(instance)    // 执行组件内 setup 函数,执行 onActivated 钩子函数进行回调函数收集    const setupResult = callWithErrorHandling(      setup,      instance,      ErrorCodes.SETUP_FUNCTION,      [__DEV__ ? shallowReadonly(instance.props) : instance.props, setupContext]    )    // currentInstance = null;    unsetCurrentInstance()  }}

最后在执行sharedContext.activatesharedContext.deactivate的时候将注册在实例上的回调函数取出来直接执行就OK了,执行时机在 postRender 之后

sharedContext.activate = (vnode, container, anchor) => {  // KeepAlive 下组件激活时执行的 move 逻辑  move(vnode, container, anchor, 0 )  // 把回调推入到 postFlush 的异步任务队列中去执行  queuePostRenderEffect(() => {    if (instance.a) {      // a是 activated 钩子的简称      invokeArrayFns(instance.a)    }  })}sharedContext.activate = (vnode, container, anchor) => {  // KeepAlive 下组件失活时执行的 move 逻辑  move(vnode, container, anchor, 0 )  queuePostRenderEffect(() => {    if (instance.da) {      // da是 deactivated 钩子的简称      invokeArrayFns(instance.da)    }  })}export const enum LifecycleHooks {  // ... 其他生命周期声明  DEACTIVATED = 'da',  ACTIVATED = 'a',}export interface ComponentInternalInstance {// ... 其他生命周期[LifecycleHooks.ACTIVATED]: Function[][LifecycleHooks.DEACTIVATED]: Function[]}

以下是关于上述demo如何实现的简化流程图

Vue中的KeepAlive组件怎么使用

需要注意的知识点

1、什么时候缓存

KeepAlive 组件的onMountedonUpdated生命周期时进行缓存

2、什么时候取消缓存
  • 缓存数量超过设置的 max 时

  • 监听 include 和 exclude 修改的时候,会读取缓存中的知进行判断是否需要清除缓存

修剪缓存的时候也要 unmount(如果该缓存不是当前组件)或者 resetShapeFlag 将标志为从 KeepAlive 相关 shapeFlag 状态重置为 STATEFUL_COMPONENT 状态(如果该缓存是当前组件,但是被exclude了),当然 unmount 函数内包含 resetShapeFlag 操作

3、缓存策略

KeepAlive 组件的缓存策略是 LRU(last recently used)缓存策略

核心思想在于需要把当前访问或渲染的组件作为最新一次渲染的组件,并且该组件在缓存修剪过程中始终是安全的,即不会被修剪。

4、如何添加到 vue devtools 组件树上

sharedContext.activate = (vnode, container, anchor) => {  // instance 是子组件实例  const instance = vnode.component!  // ...  // dev环境下设置, 自己模拟写的  devtools.emit('component:added', instance.appContext.app, instance.uid, instance.parent ? instance.parent.uid: undefined, instance)  // 官方添加  if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {    // Update components tree    devtoolsComponentAdded(instance)  }}// 同理 sharedContext.deactivates 上也要添加,不然不会显示在组件树上

5、缓存的子组件 props 更新处理

当子组件有 prop 更新时是需要重新去 patch 的,所以在 activate 的时候需要重新执行 patch 进行子组件更新

sharedContext.activate = (vnode, container, anchor) => {  // ...  // props 改变需要重新 patch(update)  patch(    instance.vnode,    vnode,    container,    anchor,    instance,    parentSuspense,    isSVG,    vnode.slotScopeIds,    optimized  )}

到此,关于“Vue中的KeepAlive组件怎么使用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Vue中的KeepAlive组件怎么使用

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Vue中的KeepAlive组件怎么使用

这篇文章主要介绍“Vue中的KeepAlive组件怎么使用”,在日常操作中,相信很多人在Vue中的KeepAlive组件怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue中的KeepAlive组件怎
2023-07-04

vue怎么自定义keepalive组件

本文小编为大家详细介绍“vue怎么自定义keepalive组件”,内容详细,步骤清晰,细节处理妥当,希望这篇“vue怎么自定义keepalive组件”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。为什么会出现这种情
2023-07-02

Vue项目中的keepAlive怎么使用

这篇“Vue项目中的keepAlive怎么使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Vue项目中的keepAlive
2023-06-30

vue中缓存组件keepalive的介绍及使用方法

这篇文章主要介绍了vue缓存组件keepalive的相关资料,keep-alive组件是使用includeexclude这两个属性传入组件名称来确认哪些可以被缓存的,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
2022-11-13

一文聊聊Vue中的KeepAlive组件

最近看 Vue 相关的知识点,看到 KeepAlive 组件时比较好奇它是怎么做到组件间切换时不重新渲染的,于是便稍微深入的了解了一下。如果你也有兴趣想要了解一下具体内部怎么实现的或者说有一定的了解但是不够熟悉,那么正好你也可以一起巩固下。
2022-11-22

vue中keepAlive组件的作用和使用方法详细介绍

这篇文章主要讲解了“vue中keepAlive组件的作用和使用方法详细介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue中keepAlive组件的作用和使用方法详细介绍”吧!前言在面试
2023-06-20

Vue组件中的父子组件使用

这篇文章主要介绍了Vue组件中的父子组件使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-01-28

vue组件库怎么使用

今天小编给大家分享一下vue组件库怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。完整项目目录结构git clone到
2023-07-04

keep-alive组件怎么在Vue中使用

这篇文章将为大家详细讲解有关keep-alive组件怎么在Vue中使用,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。 一、keep-alive 用法< keep-alive> 包裹动态组件时
2023-06-14

vue中ant-design-vue组件怎么安装与使用

这篇文章主要介绍了vue中ant-design-vue组件怎么安装与使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇vue中ant-design-vue组件怎么安装与使用文章都会有所收获,下面我们一起来看看吧
2023-06-30

vue内置组件怎么使用

这篇文章主要介绍了vue内置组件怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇vue内置组件怎么使用文章都会有所收获,下面我们一起来看看吧。vue组件有:1、component,用于渲染一个“元组件”为
2023-07-04

Vue异步组件怎么使用

本篇内容主要讲解“Vue异步组件怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Vue异步组件怎么使用”吧!1、前置要求建议使用webpack;Browserify在默认情况下不支持;2、
2023-07-04

vue缓存组件怎么使用

今天小编给大家分享一下vue缓存组件怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。在vue中,缓存组件是“keep-
2023-07-04

vue3项目中keepAlive的使用方法是什么

vue3项目中keepAlive的使用方法是什么,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。keepalive是Vue的内置组件,作用是将组件缓存在内存当中,
2023-06-22

vue子组件怎么使用父组件传过来的值

本篇内容主要讲解“vue子组件怎么使用父组件传过来的值”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“vue子组件怎么使用父组件传过来的值”吧!子组件使用父组件传过来的值父组件
2023-06-29

Vue动态组件与异步组件怎么使用

这篇“Vue动态组件与异步组件怎么使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Vue动态组件与异步组件怎么使用”文章吧
2023-07-05

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录