详细分析KeepAlive的基本知识 并缓存路由(附Demo)
目录
- 前言
- 1. 基本知识
- 2. Demo
- 2.1 基本
- 2.2 拓展
- 2.3 终极
- 3. 实战
前言
🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF
基本知识推荐阅读:KeepAlive知识点
从实战中学习,源自实战中vue路由的缓存设置
<router-view v-if="routerAlive"><template #default="{ Component, route }"><keep-alive :include="getCaches"><component :is="Component" :key="route.fullPath" /></keep-alive></template>
</router-view>
截图如下:

1. 基本知识
<KeepAlive> 内置组件,用于缓存动态组件或路由组件,以提高性能
可以保留组件的状态,避免重复渲染和生命周期钩子的重新调用
KeepAlive 作用
- 缓存组件,提高性能,避免组件反复销毁和创建
- 保留组件的状态,例如表单填写内容、滚动位置等
- 控制缓存,可以指定哪些组件需要被缓存,哪些不需要
KeepAlive 适用场景
- 需要缓存的 多页面表单
- 列表详情页切换 时,保留列表的滚动位置
- 复杂组件切换时,避免重新渲染带来的性能开销
| 功能 | 说明 |
|---|---|
| KeepAlive | 用于缓存组件,提高性能 |
| include | 指定要缓存的组件(支持字符串或数组) |
| exclude | 指定不缓存的组件 |
| max | 限制最大缓存组件数量 |
| activated() | 组件被激活时触发 |
| deactivated() | 组件被缓存时触发 |
include 和 exclude
可以通过 include 和 exclude 来决定哪些组件需要被缓存,哪些不需要
<keep-alive include="ComponentA"><component :is="currentComponent"></component>
</keep-alive>
只有 ComponentA 会被缓存,而 ComponentB 不会
或者:
<keep-alive :include="['ComponentA', 'ComponentC']"><component :is="currentComponent"></component>
</keep-alive>
只有 ComponentA 和 ComponentC 会被缓存
如果需要排除某个组件:
<keep-alive exclude="ComponentB"><component :is="currentComponent"></component>
</keep-alive>
ComponentB 不会被缓存,而其他组件都会被缓存
max —— 设置缓存组件的最大数量
如果缓存的组件较多,可以设置 max 限制最多缓存多少个组件
只缓存最近的两个组件,超出的组件会被销毁
<keep-alive :max="2"><component :is="currentComponent"></component>
</keep-alive>
KeepAlive 生命周期钩子
Vue 提供了两个专门用于 KeepAlive 组件的生命周期钩子:
activated():组件被激活(切换到缓存中的组件时调用)
deactivated():组件被缓存(切换到另一个组件时调用)
<script>
export default {created() {console.log("组件创建");},activated() {console.log("组件被激活");},deactivated() {console.log("组件被缓存");},destroyed() {console.log("组件被销毁");},
};
</script>
运行效果:
- 组件首次渲染时,created() 会触发
- 当组件切换回来时,activated() 会触发,而不会重新执行 created()
- 切换到别的组件时,deactivated() 触发,而不会执行 destroyed()
- 只有当缓存被清除时,才会执行 destroyed()
2. Demo
2.1 基本
动态组件缓存
<template><div><button @click="currentComponent = 'ComponentA'">切换到A</button><button @click="currentComponent = 'ComponentB'">切换到B</button><keep-alive><component :is="currentComponent"></component></keep-alive></div>
</template><script>
import ComponentA from "./ComponentA.vue";
import ComponentB from "./ComponentB.vue";export default {data() {return {currentComponent: "ComponentA",};},components: {ComponentA,ComponentB,},
};
</script>
组件 A (ComponentA.vue):
<template><div><h3>组件 A</h3><input v-model="text" placeholder="输入内容会被缓存" /></div>
</template><script>
export default {data() {return {text: "",};},created() {console.log("ComponentA 创建");},destroyed() {console.log("ComponentA 被销毁");},
};
</script>
组件 B (ComponentB.vue):
<template><div><h3>组件 B</h3></div>
</template><script>
export default {created() {console.log("ComponentB 创建");},destroyed() {console.log("ComponentB 被销毁");},
};
</script>
一个最明显的变化就是:
在 ComponentA 中输入一些文字,然后切换到 ComponentB,再切回来,发现输入内容还在(ComponentA 没有被销毁)
2.2 拓展
KeepAlive 也可以与 Vue Router 结合,缓存路由组件
这样在 PageA 和 PageB 之间切换时,PageA 不会被销毁,而是会被缓存
<template><div><router-link to="/pageA">页面 A</router-link><router-link to="/pageB">页面 B</router-link><keep-alive><router-view></router-view></keep-alive></div>
</template>
路由配置:
import { createRouter, createWebHistory } from "vue-router";
import PageA from "./PageA.vue";
import PageB from "./PageB.vue";const routes = [{ path: "/pageA", component: PageA },{ path: "/pageB", component: PageB },
];const router = createRouter({history: createWebHistory(),routes,
});export default router;
2.3 终极
这也是实战中常用的一种方式,从实战中抽离出基本的Demo,以 Vue 3 + Vue Router 4 + Pinia
装依赖:npm install vue-router@4 pinia
main.ts(应用入口)
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { createRouter, createWebHistory } from 'vue-router'
import App from './App.vue'
import Home from './views/Home.vue'
import About from './views/About.vue'
import Profile from './views/Profile.vue'const pinia = createPinia()// 定义路由
const routes = [{ path: '/', component: Home, name: 'Home' },{ path: '/about', component: About, name: 'About' },{ path: '/profile', component: Profile, name: 'Profile' }
]const router = createRouter({history: createWebHistory(),routes
})const app = createApp(App)
app.use(pinia)
app.use(router)
app.mount('#app')
store/tagsView.ts(Pinia 状态管理 - 维护缓存组件列表)
import { defineStore } from 'pinia'export const useTagsViewStore = defineStore('tagsView', {state: () => ({cachedViews: new Set<string>()}),getters: {getCachedViews(): string[] {return Array.from(this.cachedViews)}},actions: {addCachedView(name: string) {this.cachedViews.add(name)},removeCachedView(name: string) {this.cachedViews.delete(name)},clearCachedViews() {this.cachedViews.clear()}}
})
App.vue(KeepAlive 组件封装)
<script setup lang="ts">
import { computed, ref, provide, nextTick } from 'vue'
import { useTagsViewStore } from './store/tagsView'
import { RouterView } from 'vue-router'const tagsViewStore = useTagsViewStore()
const getCaches = computed(() => tagsViewStore.getCachedViews)// 无感刷新功能
const routerAlive = ref(true)
const reload = () => {routerAlive.value = falsenextTick(() => (routerAlive.value = true))
}
provide('reload', reload)
</script><template><div><router-view v-if="routerAlive"><template #default="{ Component, route }"><keep-alive :include="getCaches"><component :is="Component" :key="route.fullPath" /></keep-alive></template></router-view></div>
</template>
views/Home.vue
<script setup lang="ts">
import { inject } from 'vue'const reload = inject('reload') as () => void
</script><template><div><h1>Home Page</h1><button @click="reload">刷新当前组件</button></div>
</template>
views/About.vue
<template><div><h1>About Page</h1></div>
</template>
views/Profile.vue
<template><div><h1>Profile Page</h1></div>
</template>
动态路由的常用操作
- 动态添加路由
在 router.ts 中可以动态添加路由:
import router from './router'const newRoute = {path: '/new-page',component: () => import('@/views/NewPage.vue'),name: 'NewPage'
}router.addRoute(newRoute)
-
动态移除路由:
router.removeRoute('NewPage') -
监听路由变化
import { useRoute, useRouter } from 'vue-router'
import { watch } from 'vue'const route = useRoute()
const router = useRouter()watch(() => route.fullPath, (newPath) => {console.log('路由发生变化:', newPath)
})
3. 实战
以ruoyi-vue-pro实战的Demo进行讲解,源码:芋道源码/ruoyi-vue-pro
具体KeepAlive,其文件在App.vue中
<router-view v-if="routerAlive"><template #default="{ Component, route }"><keep-alive :include="getCaches"><component :is="Component" :key="route.fullPath" /></keep-alive></template>
</router-view>
通过组件的设置是否路由进行缓存,后续获取到这个路由信息时,对应判定是否该路由有缓存信息
const getCaches = computed((): string[] => {const caches = tagsViewStore.getCachedViewsconsole.log('当前缓存的组件:', caches) // 打印缓存的组件名称return caches
})const tagsView = computed(() => appStore.getTagsView)//region 无感刷新
const routerAlive = ref(true)
// 无感刷新,防止出现页面闪烁白屏
const reload = () => {routerAlive.value = falsenextTick(() => (routerAlive.value = true))
}
// 为组件后代提供刷新方法
provide('reload', reload)
对应的tagsView信息如下:

后续在tsx中进行引用

后续新增路由的时候,其路由地址 要和 defineOptions({ name: 'xxx' }) 对应一致
相关文章:
详细分析KeepAlive的基本知识 并缓存路由(附Demo)
目录 前言1. 基本知识2. Demo2.1 基本2.2 拓展2.3 终极 3. 实战 前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 基本知识推荐阅读:KeepAlive知识点 从实战中学习,源自实战中vue路由的…...
【Go】Go viper 配置模块
1. 配置相关概念 在项目开发过程中,一旦涉及到与第三方中间件打交道就不可避免的需要填写一些配置信息,例如 MySQL 的连接信息、Redis 的连接信息。如果这些配置都采用硬编码的方式无疑是一种不优雅的做法,有以下缺陷: 不同环境…...
zabbix“专家坐诊”第277期问答
在线答疑:乐维社区 问题一 Q:这个怎么解决呢? A:缺少这个依赖。 Q:就一直装不上。 A:装 zabbix-agent2-7.0.0-releasel.el7.x86 64 需要前面提示的那个依赖才可以装。 问题二 Q:大佬,如果agen…...
大模型工程师学习日记(十一):FAISS 高效相似度搜索和密集向量聚类的库
Facebook AI Similarity Search (Faiss /Fez/) 是一个用于高效相似度搜索和密集向量聚类的库。它包含了在任意大小的向量集合中进行搜索的算法,甚至可以处理可能无法完全放入内存的向量集合。它还包含用于评估和参数调整的支持代码。 Faiss 官方文档:We…...
python学习第三天
条件判断 条件判断使用if、elif和else关键字。它们用于根据条件执行不同的代码块。 # 条件判断 age 18 if age < 18:print("你还是个孩子!") elif age 18:print("永远十八岁!") else:print("你还年轻!")…...
深入解析 Svelte:下一代前端框架的革命
深入解析 Svelte:下一代前端框架的革命 1. Svelte 简介 Svelte 是一款前端框架,与 React、Vue 等传统框架不同,它采用 编译时(Compile-time) 方式来优化前端应用。它不像 React 或 Vue 依赖虚拟 DOM,而是…...
C++20 中位移位运算符的统一行为:深入解析与实践指南
文章目录 1. 位移位运算符的基础1.1 左移运算符(<<)1.2 右移运算符(>>) 2. C20 对位移位运算符的统一2.1 移位数量超出操作数位宽2.2 负数移位 3. 实践中的注意事项4. 示例代码5. 总结 在 C 的发展历程中,…...
Linux——基本指令
我们今天学习Linux最基础的指令 ls 指令 语法: ls [选项] [⽬录或⽂件] 功能:对于⽬录,该命令列出该⽬录下的所有⼦⽬录与⽂件。对于⽂件,将列出⽂件名以及其他信 息。 命令中的选项,一次可以传递多个 ,…...
MySql面试总结(二)
WHERE 子句优化 截至2024年7月,MySQL最新稳定版本是8.2,并不存在MySQL 8.4 。下面从常见的几个方面为你介绍 MySQL 8.x 中 WHERE 子句的优化方法: 1. 确保使用索引 原理:索引可以加快数据的查找速度,当 WHERE 子句中的条件列有索引时,MySQL 可以直接定位到符合条件的数…...
Pytorch中的主要函数
目录 一、torch.manual_seed(seed)二、torch.cuda.manual_seed(seed)三、torch.rand(*size, outNone, dtypeNone, layouttorch.strided, deviceNone, requires_gradFalse)四、给大家写一个常用的自动选择电脑cuda 或者cpu 的小技巧五、torch.version.cuda;torch.bac…...
Java实现大数据量导出报表
一、实现方式 在Java中,导出数据到Excel有多种方式,每种方式都有其优缺点,适用于不同的场景。以下是常见的几种方式及其特点: 1.1 Apache POI Apache POI 是 Java 中最流行的库,支持读写 Excel 文件(包括…...
大语言模型 智能助手——既能生成自然语言回复,又能在必要时调用外部工具获取实时数据
示例代码: import json from langgraph.graph import Graph, END,StateGraph from langchain_core.utils.function_calling import convert_to_openai_function from langchain_community.tools.openweathermap import OpenWeatherMapQueryRun from langchain_core…...
PyTorch 系统教程:理解机器学习数据分割
数据分割是机器学习中的一个基本概念,它直接影响模型的性能和泛化。在本文中,我们将深入研究为什么数据分割在机器学习中很重要,并演示如何使用PyTorch有效地实现它。 理解数据分割 数据分割是将数据集划分为单独的组以进行训练、验证和测试…...
分水岭算法(Watershed Algorithm)教程:硬币分割实例
import cv2 import numpy as np# 1. 图像预处理 img cv2.imread("./water/water_coins.jpeg") gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, thresh cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV cv2.THRESH_OTSU) kernel np.ones((3, 3), np.int8)…...
【STM32项目实战系列】基于STM32G474的FDCAN驱动配置
前言:本周工作中用到了CANFD的驱动,由于以前都是用到的CAN2.0,所以过程并不是特别的顺利,所以中间遇到几个比较小的问题导致自己卡住了一段时间,特此记录一下并完全奉上自己的配置的源码。 1,CANFD配置与简…...
shell文本处理
shell文本处理 一、grep 过滤来自一个文件或标准输入匹配模式内容。除了 grep 外,还有 egrep、fgrep。egrep 是 grep 的扩展,相当于 grep -E。fgrep 相当于 grep -f,用的比较少。 用法 grep [OPTION]... PATTERN [FILE]...支持的正则描述…...
如何利用客户端双向TLS认证保护云上应用安全
双向TLS(mTLS)通过要求服务器和客户端双方使用数字证书来验证彼此身份,从而扩展了传统TLS的安全性。常规的TLS只会验证服务器的身份(如大家的浏览器在验证网站时的场景),而mTLS确保在任何数据交换发生之前,双方都对彼此持有信任。在本文中&am…...
nlp第十节——LLM相关
一、模型蒸馏技术 本质上是从一个大模型蒸馏出小模型,从小模型训练出来的概率分布(如自回归模型预测下一个字的概率分布)分别与大模型预测的概率分布和ground label求loss。与大模型预测的概率分布用KL散度求loss,与ground label用…...
T-SQL 语言基础: SQL 数据库对象元数据及配置信息获取
目录 介绍目录视图 获取表和架构名称获取列信息 信息架构视图 获取表信息获取列信息 系统存储过程和函数 获取对象列表获取对象详细信息获取约束信息获取数据库属性信息 总结引用 介绍 在 SQL 数据库管理中,获取数据库对象的元数据信息是至关重要的。元数据提供了…...
ue5 创建多列StreeView的方法与理解
创建StreeView的多列样式怎么就像是创建单行单列差不多?貌似就是在单行单列中加入了多列widget? 示例代码 DetailTabWidget #pragma once #include "TreeViewItemBase.h"class SDetailTabWidget : public SCompoundWidget {SLATE_BEGIN_ARGS(SDetailT…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...
