当前位置: 首页 > news >正文

Vue 3 的 keep-alive 及生命周期钩子

在 Vue 3 中,keep-alive 是一个内置组件,用于提高性能和减少不必要的组件销毁与重建。它与组件的生命周期紧密相关,特别是在动态组件和路由切换场景下,能够缓存组件的状态并避免重新渲染。 

而 onActivated 和 onDeactivated 是 Vue3 Composition API 提供的钩子函数,专门用于处理被 keep-alive 缓存组件的激活和销毁逻辑。

1. keep-alive

1.1 什么是 keep-alive?

在 Vue 中,keep-alive 是一个内置的高阶组件,用于缓存不再活跃的组件实例,使其在不再渲染时依然保留状态。通过,在需要频繁切换视图组件或动态组件时使用 keep-alive,这样可以避免频繁销毁和重新创建组件,从而提高性能。

eg:很多情况下,当在多个选项卡或页面之间切换时,可能会希望保留每个选项卡的状态,而不是每次切换时都销毁再重新加载它们。此时,keep-alive 就可以解决这个问题。

1.2 基本使用

keep-alive 可以包裹动态组件或页面,当使用时,它会缓存已渲染的组件,并将其状态保持在内存中。当组件再次被激活时,keep-alive 会复用该组件的实例,而不是重新创建一个新的组件。

🌰 子组件 A + B 类似

<template><div><h2>这是组件A</h2><p>这是组件A的内容</p></div>
</template><script>
export default {name: 'ComponentA',mounted() {console.log('ComponentA 被挂载');},unmounted() {console.log('ComponentA 被卸载');},
};
</script>

App. vue

<template><div><button @click="switchComponent">切换组件</button><keep-alive><component :is="currentComponent"></component></keep-alive></div>
</template><script>
import { defineComponent, ref } from 'vue';
import ComponentA from './components/ComponentA.vue';
import ComponentB from './components/ComponentB.vue';export default defineComponent({name: 'App',setup() {// 当前渲染的组件,直接引用组件const currentComponent = ref(ComponentA);// 切换组件的逻辑const switchComponent = () => {currentComponent.value = JSON.stringify(currentComponent.value) === JSON.stringify(ComponentA) ? ComponentB : ComponentA;};return {currentComponent,switchComponent,};},
});
</script>

展示如下:

点击切换

切换后,A 组件被缓存而不是被销毁,再次切换回来 B 组件被缓存,A 组件重新渲染。

如果不使用 keep-alive 表现为:

<template><div><button @click="switchComponent">切换组件</button><component :is="currentComponent"></component></div>
</template>

组件先被销毁然后创建。 

小 Tip 1

下面写法展示组件失败,为什么呢?

根本原因是,在 setup() 中使用的是字符串 'ComponentA' 和 'ComponentB',而在 keep-alive 和 component 组件的 :is 属性中,Vue 期望的是组件本身,而不是它的字符串名称。

因此需要将 currentComponent 的值设置为 组件的引用。

export default defineComponent({name: 'App',setup() {// 当前渲染的组件const currentComponent = ref('ComponentA');// 切换组件的逻辑const switchComponent = () => {currentComponent.value = currentComponent.value === 'ComponentA' ? 'ComponentB' : 'ComponentA';};return {currentComponent,switchComponent,};},
});
小 Tip 2

上面图片右侧控制台出现黄色警告⚠️,说明在 ref 中存储了一个 Vue 组件实例的响应式对象,而 Vue 会自动将其变成响应式,这可能会带来性能问题,为了避免这个情况,Vue 建议使用 markRaw 或 shallowRef 避免组件变成响应式对象。

解决方法

1、使用 markRaw

markRaw 会阻止 Vue 对传入对象进行响应式处理,它是 Vue 提供的一个优化方法,适用于那些不需要响应式处理的对象(比如组件)。

// 使用 markRaw 来避免组件变成响应式
const currentComponent = ref(markRaw(ComponentA));

2、使用 shallowRef(推荐)

shallowRef 是 Vue 3 提供的一个 API,类似于 ref,但它只会让引用的对象本身变得响应式,而不会递归地将对象中的嵌套属性变成响应式。对于 Vue 组件,使用 shallowRef 会更加合适,因为我们只关心组件本身的引用,而不需要其内部的响应式。

// 使用 shallowRef 来避免组件变成深度响应式
const currentComponent = shallowRef(ComponentA);

1.3 include 和 exclude 属性

keep-alive 还提供了 include 和 exclude 属性,用于控制哪些组件应该被缓存,哪些组件不应该被缓存。

- include:一个字符串、正则表达式或数组,指定哪些组件应该被缓存。

- exclude:一个字符串、正则表达式或数组,指定哪些组件不应该被缓存。

🌰

<template><div><button @click="switchComponent">切换组件</button><keep-alive :include="['ComponentA']" :exclude="['ComponentB']"><component :is="currentComponent"></component></keep-alive></div>
</template>
<script>
import { defineComponent, shallowRef } from 'vue';
import ComponentA from './components/ComponentA.vue';
import ComponentB from './components/ComponentB.vue';export default defineComponent({name: 'App',setup() {const currentComponent = shallowRef(ComponentA);const switchComponent = () => {currentComponent.value = JSON.stringify(currentComponent.value) === JSON.stringify(ComponentA) ? ComponentB : ComponentA;};return {currentComponent,switchComponent,};},
});
</script>

只有 ComponentA 会被缓存,ComponentB 不会。根据实际需要灵活控制哪些组件需要被缓存。

2. 钩子函数

2.1 onActivated

onActivated 钩子会在组件被缓存并重新激活时触发。通常情况下,组件被 keep-alive 缓存后,如果用户切换到该组件,Vue 会复用这个组件的实例并调用 onActivated 钩子。

使用场景:需要在组件激活时重新加载数据、执行某些操作(eg:开启动画、更新状态等)。

2.2 onDeactivated

与 onActivated 类似,onDeactivated 会在组件被缓存并从 keep-alive 中移除时触发。此时,组件的状态会被保留,但它的 DOM 和实例会被销毁,当再次激活时,onActivated 会重新触发。

使用场景:需要在组件去激活时清理资源,例如停止计时器、清理事件监听器等。或进行一些状态重置操作。

2.3 🌰

注意:这两个钩子函数只有在组件被 <keep-alive> 包裹,且组件经历过激活和停用的过程,也就是组件需要在显示和隐藏之间切换,而不是一直保持显示状态。

子组件

<template><div><h3>子组件</h3></div>
</template><script setup>
import { onActivated, onDeactivated } from 'vue';// 在组件激活时重新加载数据
onActivated(() => {console.log('组件被激活,重新加载数据');
});// 在组件停用时清理数据
onDeactivated(() => {console.log('组件被停用,清理数据或停止操作');
});
</script>

App.vue

<template><div><keep-alive><Info v-if="isActive" /></keep-alive><button @click="toggleActive">切换显示</button></div>
</template><script setup>
import { ref } from 'vue';
import Info from './components/Info.vue';const isActive = ref(true);const toggleActive = () => {isActive.value = !isActive.value;
};
</script>

展示为:

小 Tip 3 

上面🌰使用 v-if 控制组件的显示和隐藏,如果使用 v-show 呢?

<template><div><button @click="toggleActive">切换组件显示</button><keep-alive><UserInfo v-show="isActive" /></keep-alive></div>
</template>

结果是:不会触发。

如果使用 v-show 控制组件显示和隐藏,不会触发两个钩子的执行,因为其是通过修改 display 属性来显示或隐藏 DOM 元素,而不会销毁和重新渲染组件。

2.4 存在问题 

1、缓存时的副作用

当组件被缓存时,它的状态会保留在内存中,不会被销毁。如果需要清理某些副作用(例如,清理计时器、停止网络请求等),应该在 onDeactivated 中进行处理。

onDeactivated(() => {// 停止任何异步任务或计时器clearInterval(someTimer)console.log('停止异步任务')
})

2、性能问题

如果 onActivated 钩子执行了某些耗时操作(如数据请求、定时任务等),可能会影响用户体验。为了避免影响性能,可以在 onActivated 中进行懒加载操作,只在需要时执行某些任务。

onActivated(() => {if (!info.value) {fetchData()  // 如果没有数据才加载}
})

3. keep-alive 与路由结合 

3.1 在 Vue 路由中使用 keep-alive

Vue 路由通常与 keep-alive 一起使用,特别是在单页面应用(SPA)中。当切换路由时,希望某些页面保持活跃并缓存其状态。keep-alive 可以用来缓存路由视图组件,避免在路由切换时销毁和重新渲染。

<template><keep-alive><router-view></router-view></keep-alive>
</template><script>
export default {// 使用 keep-alive 包裹 router-view,使得路由切换时组件能够缓存
};
</script>

router-view 是 Vue 路由用于渲染当前匹配的路由组件,keep-alive 缓存路由组件,当路由切换时,之前的组件不会被销毁,而是保持活跃并缓存状态。

3.2 动态路由

keep-alive 的 include 和 exclude 属性可以用来动态控制哪些路由视图组件应该被缓存,哪些不应该被缓存。

<template><div><h1>动态路由和 keep-alive</h1><keep-alive :include="['Home', 'About']"><router-view></router-view></keep-alive></div>
</template><script>
export default {data() {return {// 只有 Home 和 About 组件会被缓存}},
}
</script>

路由配置:

import { createRouter, createWebHistory } from 'vue-router';
import Home from './components/Home.vue';
import About from './components/About.vue';
import Contact from './components/Contact.vue';const routes = [{path: '/',name: 'Home',component: Home,},{path: '/about',name: 'About',component: About,},{path: '/contact',name: 'Contact',component: Contact,},
];const router = createRouter({history: createWebHistory(),routes,
});export default router;

同理:

<keep-alive :exclude="['Contact']"><router-view></router-view>
</keep-alive>

根据具体情况来控制缓存策略,从而有效提升性能,并节省内存。

总结:使用 keep-alive 时,路由切换时被缓存的组件会保持其状态。例如,表单输入的数据、滚动位置等都不会丢失。为了确保在缓存组件时能保持状态,可以使用 onActivated 和 onDeactivated 钩子函数执行一些操作。

相关文章:

Vue 3 的 keep-alive 及生命周期钩子

在 Vue 3 中&#xff0c;keep-alive 是一个内置组件&#xff0c;用于提高性能和减少不必要的组件销毁与重建。它与组件的生命周期紧密相关&#xff0c;特别是在动态组件和路由切换场景下&#xff0c;能够缓存组件的状态并避免重新渲染。 而 onActivated 和 onDeactivated 是 …...

ComfyUI实现老照片修复——AI修复老照片(ComfyUI-ReActor / ReSwapper)解决天坑问题及加速pip下载

AI修复老照片&#xff0c;试试吧&#xff0c;不一定好~~哈哈 2023年4月曾用过ComfyUI&#xff0c;当时就感慨这个工具和虚幻的蓝图很像&#xff0c;以后肯定是专业人玩的。 2024年我写代码去了&#xff0c;AI做图没太关注&#xff0c;没想到&#xff0c;现在ComfyUI真的变成了工…...

OpenEuler学习笔记(十一):OpenEuler上搭建LAMP环境

LAMP环境指的是Linux、Apache、MySQL&#xff08;或MariaDB&#xff09;和PHP的组合&#xff0c;下面为你介绍在OpenEuler上搭建LAMP环境的详细步骤&#xff1a; 1. 系统更新 首先要更新系统中的软件包&#xff0c;保证系统处于最新状态。 sudo dnf update -y2. 安装Apache…...

Mongodb 慢查询日志分析 - 1

Mongodb 慢查询日志分析 使用 mloginfo 处理过的日志会在控制台输出, 显示还是比较友好的. 但是如果内容较大, 就不方便查看了, 如果可以导入到 excel 就比较方便筛选/排序. 但是 mloginfo 并没有提供生成到 excel 的功能. 可以通过一个 python 脚本辅助生成: import pandas…...

MySQL面试题2025 每日20道【其四】

1、你们生产环境的 MySQL 中使用了什么事务隔离级别&#xff1f;为什么&#xff1f; 中等 在生产环境中&#xff0c;MySQL数据库的事务隔离级别通常由开发团队或数据库管理员根据应用的需求来设定。MySQL支持四种标准的事务隔离级别&#xff1a; 读未提交&#xff08;Read Unc…...

微服务学习-Nacos 注册中心实战

1. 注册中心的设计思路 1.1. 微服务为什么会用到注册中心&#xff1f; 服务与服务之间调用需要有服务发现功能&#xff1b;例如订单服务调用库存服务&#xff0c;库存服务如果有多个&#xff0c;订单服务到底调用那个库存服务呢&#xff08;负载均衡器&#xff09;&#xff0…...

k8s服务StatefulSet部署模板

java 服务StatefulSet部署模板 vim templates-test.yamlapiVersion: apps/v1 kind: StatefulSet metadata:labels:app: ${app_labels}name: ${app_name}namespace: ${app_namespace} spec:replicas: ${app_replicas_count}selector:matchLabels:app: ${app_labels}template:la…...

07 区块链安全技术

概述 区块链的安全特性 区块链解决了在不可靠网络上可靠地传输信息的难题&#xff0c;由于不依赖与中心节点的认证和管理&#xff0c;因此防止了中心节点被攻击造成的数据泄露和认证失败的风险。 区块链安全防护的三大特点 共识机制代替中心认证机制数据篡改“一发动全身”…...

Adobe的AI生成3D数字人框架:从自拍到生动的3D化身

一、引言 随着人工智能技术的发展,我们见证了越来越多创新工具的出现,这些工具使得图像处理和视频编辑变得更加智能与高效。Adobe作为全球领先的创意软件公司,最近推出了一项令人瞩目的新技术——一个能够将普通的二维自拍照转换成栩栩如生的三维(3D)数字人的框架。这项技…...

dfs专题四:综合练习

key&#xff1a;画出决策树&#xff08;就是找个简单例子模拟一下的树状决策图&#xff09; dfs传参 or 全局变量&#xff1a; int, double等常量/比较小的变量&#xff0c;可以dfs参数传递vector等线性O&#xff08;N&#xff09;变量&#xff0c;要用全局变量 回溯&#x…...

【线性代数】列主元法求矩阵的逆

列主元方法是一种用于求解矩阵逆的数值方法&#xff0c;特别适用于在计算机上实现。其基本思想是通过高斯消元法将矩阵转换为上三角矩阵&#xff0c;然后通过回代求解矩阵的逆。以下是列主元方法求解矩阵 A A A 的逆的步骤&#xff1a; [精确算法] 列主元高斯消元法 步骤 1&am…...

大写——蓝桥杯

1.题目描述 给定一个只包含大写字母和小写字母的字符串&#xff0c;请将其中所有的小写字母转换成大写字母后将字符串输出。 输入描述 输入一行包含一个字符串。 输出描述 输出转换成大写后的字符串。 输入输出样例 示例 输入 LanQiao输出 LANQIAO评测用例规模与约定 对…...

HTML `<head>` 元素详解

在 HTML 文档中&#xff0c;<head> 元素是一个非常重要的部分&#xff0c;它包含了文档的元数据&#xff08;metadata&#xff09;和其他与文档相关的信息。虽然 <head> 中的内容不会直接显示在网页上&#xff0c;但它对网页的行为、样式和搜索引擎优化&#xff08…...

一文速通stack和queue的理解与使用

CSTL之stack和queue 1.stack1.1.stack的基本概念1.2.stack的接口 2.queue2.1.queue的基本概念2.2.queue的接口 3.priority_queue3.1.priority_queue的基本概念3.2.priority_queue的接口3.3.仿函数 4.容器适配器5.deque5.1.deque的简单了解5.2.deque的优缺点 &#x1f31f;&…...

Antd React Form使用Radio嵌套多个Select和Input的处理

使用Antd React Form使用Radio会遇到嵌套多个Select和Input的处理&#xff0c;需要多层嵌套和处理默认事件和冒泡&#xff0c;具体实现过程直接上代码。 实现效果布局如下图 代码 <Formname"basic"form{form}labelWrap{...formItemLayoutSpan(5, 19)}onFinish{on…...

Vue - toRefs() 和 toRef() 的使用

一、toRefs() 在 Vue 3 中,toRefs()可以将响应式对象的属性转换为可响应的 refs。主要用于在解构响应式对象时&#xff0c;保持属性的响应性。 1. 导入 toRefs 函数 import { toRefs } from vue;2. 将响应式对象的属性转换为 ref const state reactive({count: 0,message:…...

Python3 OS模块中的文件/目录方法说明九

一. 简介 前面文章简单学习了 Python3 中 OS模块中的文件/目录的部分函数。 本文继续来学习 OS 模块中文件、目录的操作方法&#xff1a;os.pipe() 方法、os.popen() 方法。 二. Python3 OS模块中的文件/目录方法 1. os.pipe() 方法 os.pipe() 方法用于创建一个管道, 返回…...

OpenCV文字绘制支持中文显示

OpenCV版本&#xff1a;4.4 IDE&#xff1a;VS2019 功能描述 OpenCV绘制文本的函数putText()不支持中文的显示&#xff0c;网上很多方法推荐的都是使用FreeType来支持&#xff0c;FreeType是什么呢&#xff1f;FreeType的官网上有介绍 FreeType官网 https://www.freetype.or…...

opengrok_windows_多工程环境搭建

目录 多工程的目录 工程代码下载和log配置 工程的索引 工程部署 工程测试 参考列表 多工程的目录 工程代码下载和log配置 工程代码下载 在每个工程的src目录下&#xff0c;下载工程代码&#xff0c;以下载pulseaudio的代码为例。 git clone gitgithub.com…...

基于ollama,langchain,springboot从零搭建知识库三【解析文档并存储到向量数据库】

安装环境 安装pgvector&#xff0c;先设置docker镜像源&#xff1a; vim /etc/docker/daemon.json {"registry-mirrors": ["https://05f073ad3c0010ea0f4bc00b7105ec20.mirror.swr.myhuaweicloud.com","https://mirror.ccs.tencentyun.com",&…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

基于Flask实现的医疗保险欺诈识别监测模型

基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施&#xff0c;由雇主和个人按一定比例缴纳保险费&#xff0c;建立社会医疗保险基金&#xff0c;支付雇员医疗费用的一种医疗保险制度&#xff0c; 它是促进社会文明和进步的…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题&#xff0c;前来答题。 每个人对刷题理解是不同&#xff0c;有的人是看了writeup就等于刷了&#xff0c;有的人是收藏了writeup就等于刷了&#xff0c;有的人是跟着writeup做了一遍就等于刷了&#xff0c;还有的人是独立思考做了一遍就等于刷了。…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

R 语言科研绘图第 55 期 --- 网络图-聚类

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…...

Unity中的transform.up

2025年6月8日&#xff0c;周日下午 在Unity中&#xff0c;transform.up是Transform组件的一个属性&#xff0c;表示游戏对象在世界空间中的“上”方向&#xff08;Y轴正方向&#xff09;&#xff0c;且会随对象旋转动态变化。以下是关键点解析&#xff1a; 基本定义 transfor…...