本文技术栈:vue3 + ts + pinia
相关推荐:nuxt2:keepalive 列表页到详情,详情回到列表,列表恢复离开时的状态
<KeepAlive>
是一个内置组件,它的功能是在多个组件间动态切换时缓存被移除的组件实例。
keepalive组件总共有三个参数
include:可传字符串、正则表达式、数组,名称匹配成功的组件会被缓存
exclude:可传字符串、正则表达式、数组,名称匹配成功的组件不会被缓存
max:可传数字,限制缓存组件的最大数量,默认为10
include包含的 && 排除exclude包含的 就是需要缓存的组件
<keep-alive :include="" :exclude="" :max=""></keep-alive>
二、使用场景
在列表页面 点击查看 路由到详情页面
详情页面点击返回,希望回到当时从列表页面离开时的样子
(因为列表页经过了tab切换,表单查询,分页查询等操作,如果回到列表页是一个初始的状态,那么需要重新操作这一系列动作)
三、全局实现keepalive
3.1、App.vue
<template>
<!-- <router-view></router-view> -->
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
</template>
<script setup lang="ts">
onErrorCaptured(err => {
console.log('Caught error', err)
return false
})
</script>
<style scoped>
</style>
3.2、src/views/keepaliva/index.vue
<template>
<div class="container">
<div>keep-alive</div>
<div>
<el-input v-model="KValue"></el-input>
</div>
<div>
<router-link to='/keepalive-snow'>
<button>keep-aliva-snow</button>
</router-link>
</div>
</div>
</template>
<script setup lang="ts">
const KValue = ref('')
</script>
<style scoped lang="less">
</style>
3.3、src/views/keepaliva/snow.vue
<template>
<div class="container">
<div>keep-alive</div>
<div>
<el-input v-model="KValue"></el-input>
</div>
<div>
<router-link to='/keepalive'>
<button>keep-aliva</button>
</router-link>
</div>
</div>
</template>
<script setup lang="ts">
const KValue = ref('')
</script>
<style scoped lang="less">
</style>
至此,简单的keepalive demo已实现。生产项目使用肯定不能这么暴力,本文继续介绍其他内容以满足生产使用。
四、router配置缓存
4.1、App.vue
<template>
<!-- <router-view></router-view> -->
<router-view v-slot="{ Component }">
<component :is="Component" v-if="!$route.meta.keepAlive" :key="$route.path" />
<keep-alive>
<component :is="Component" v-if="$route.meta.keepAlive" :key="$route.path" />
</keep-alive>
</router-view>
</template>
<script setup lang="ts">
onErrorCaptured(err => {
console.log('Caught error', err)
return false
})
</script>
<style scoped>
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
filter: drop-shadow(0 0 2em #42b883aa);
}
</style>
4.2、src/routers/index.vue
{
path: '/keepalive', // keepalive
component: ()=>import('../views/keepalive/index.vue'),
meta: {
keepAlive: true // 该页面需要keepAlive
}
},
{
path: '/keepalive-snow', // keepalive
component: ()=>import('../views/keepalive/snow.vue'),
meta: {
keepAlive: true // 该页面需要keepAlive
}
},
4.3、src/views/keepaliva/index.vue
<template>
<div class="container">
<div>keep-alive</div>
<div>
<el-input v-model="KValue"></el-input>
</div>
<div>
<router-link to='/keepalive-snow'>
<button>keep-aliva-snow</button>
</router-link>
</div>
</div>
</template>
<script setup lang="ts">
const KValue = ref('')
onActivated(() => {
// 调用时机为首次挂载
// 以及每次从缓存中被重新插入时
console.log('a-onActivated')
})
onDeactivated(() => {
// 在从 DOM 上移除、进入缓存
// 以及组件卸载时调用
console.log('a-onDeactivated')
})
</script>
<style scoped lang="less">
</style>
4.4、src/views/keepaliva/snow.vue
<template>
<div class="container">
<div>keep-alive-snow</div>
<div>
<el-input v-model="KValue"></el-input>
</div>
<div>
<router-link to='/keepalive'>
<button>keep-aliva</button>
</router-link>
</div>
</div>
</template>
<script setup lang="ts">
const KValue = ref('')
onActivated(() => {
// 调用时机为首次挂载
// 以及每次从缓存中被重新插入时
console.log('b-onActivated')
})
onDeactivated(() => {
// 在从 DOM 上移除、进入缓存
// 以及组件卸载时调用
console.log('b-onDeactivated')
})
</script>
<style scoped lang="less">
</style>
五、layouts配置keepalive--router配置
5.1、src/routers/index.vue
{
path: '/menu', // keepalive
component: layout_menu,
name: 'menu',
children: [
{
path: 'keepalive',
component: ()=>import('../views/keepalive/index.vue'),
name: 'keepalive',
meta: {
keepAlive: true // 该页面需要keepAlive
}
}
],
meta: {
keepAlive: true // 该页面需要keepAlive
}
},
{
path: '/menu', // keepalive
component: layout_menu,
name: 'menu2',
children: [
{
path: 'keepalivesnow',
component: ()=>import('../views/keepalive/snow.vue'),
name: 'keepalivesnow',
meta: {
keepAlive: true // 该页面需要keepAlive
}
}
],
meta: {
keepAlive: true // 该页面需要keepAlive
}
},
5.2、layouts/menu/index.vue
<!-- src/layouts/default/index.vue -->
<template>
<el-container>
<el-container>
<el-header>
<el-button @click="tomenu1">menu1</el-button>
<el-button @click="tomenu2">menu2</el-button>
</el-header>
<el-main>
<!-- 子路由出口 -->
<!-- <router-view /> -->
<router-view v-slot="{ Component }">
<component :is="Component" v-if="!$route.meta.keepAlive" :key="$route.path" />
<keep-alive>
<component :is="Component" v-if="$route.meta.keepAlive" :key="$route.path" />
</keep-alive>
</router-view>
</el-main>
</el-container>
</el-container>
</template>
<script setup lang="ts">
import { useRouter } from "vue-router"
const router = useRouter()
const tomenu1 = ()=>{
router.push({
path: '/menu/keepalive'
})
}
const tomenu2 = ()=>{
console.log('28')
router.push({
path: '/menu/keepalivesnow'
})
}
</script>
<style scoped lang="less">
.el-container {
height: 100vh;
}
.el-header {
background-color: #B3C0D1;
color: #ff0000;
}
.el-main {
background-color: #E9EEF3;
}
</style>
六、layouts配置keepalive--组件配置--推荐方法
本方法实现在layout文件配置keepalive,思路与方法满足生产环境使用。
点击菜单时候清空所有缓存的组件,点击查看时候缓存对应的组件,满足spa单页面项目生产使用。
实现在列表页经过一系列操作后,点查看到详情页,点返回回到列表页--列表页恢复离开时的状态,点击菜单恢复到没有缓存的页面展示最新的数据。推荐使用。
6.1、参数介绍
include:可传字符串、正则表达式、数组,名称匹配成功的组件会被缓存
exclude:可传字符串、正则表达式、数组,名称匹配成功的组件不会被缓存
max:可传数字,限制缓存组件的最大数量,默认为10
include包含的 && 排除exclude包含的 就是需要缓存的组件
6.2、layouts/menu/index.vue
<!-- src/layouts/default/index.vue -->
<template>
<el-container>
<el-container>
<el-header>
<el-button @click="toList">列表页</el-button>
<el-button @click="toDetail">详情页</el-button>
<el-button @click="clearPinia">恢复KeepAlive</el-button>
</el-header>
<el-main>
<!-- 子路由出口 -->
<!-- <router-view /> -->
<router-view v-slot="{ Component }">
<keep-alive :include="includeArr" :exclude="excludeArr" :max="10">
<component :is="Component" :key="$route.path" />
</keep-alive>
</router-view>
</el-main>
</el-container>
</el-container>
</template>
<script setup lang="ts">
import { useRouter } from "vue-router"
import { useKeepStore } from '@/views/stores/keepalive'
const keepStoreData = useKeepStore()
// 这里需要使用computed,否则清空excludeArr不起作用
let includeArr = computed(()=>{
return keepStoreData.includeArr
})
// 这里需要使用computed,否则清空excludeArr不起作用
let excludeArr = computed(()=>{
return keepStoreData.excludeArr
})
const router = useRouter()
const toList = ()=>{
keepStoreData.includeArr = []
router.push({
path: '/menu/keepalive'
})
}
const toDetail = ()=>{
keepStoreData.includeArr = []
router.push({
path: '/menu/keepalivesnow'
})
}
const clearPinia = ()=>{
keepStoreData.includeArr = ['keepalive','keepalivesnow']
}
</script>
<style scoped lang="less">
.el-container {
height: 100vh;
}
.el-header {
background-color: #B3C0D1;
color: #ff0000;
}
.el-main {
background-color: #E9EEF3;
}
</style>
6.3、 设置name
6.3.1安装插件
vite-plugin-vue-setup-extend
6.3.2、vite.config.ts
引入插件
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
使用插件
plugins: [vue(),VueSetupExtend()],
6.3.3、页面使用
<script setup lang="ts" name="keepalive">
6.4、src/routers/index.vue
同文本 5.1
6.5、src/views/keepaliva/index.vue
<template>
<div class="container">
<div>keep-alive-list-列表页面</div>
<div>
<span>接口数据:</span>
<span v-for="(item, index) in nameList" :key="index">{
{ item }}</span>
</div>
<div class="keep-table">
<el-table :data="tableData" style="width: 500px">
<el-table-column prop="name" label="Name" width="180" />
<el-table-column prop="address" label="Address" />
</el-table>
</div>
<div class="keep-pagination">
<el-pagination
layout="prev, pager, next"
v-model:current-page="currentPage"
:page-size="1"
:total="total"
@current-change="handleCurrentChange"
/>
</div>
<div>
<span>输入框:</span>
<el-input v-model="KValue"></el-input>
</div>
<div>
<!-- <router-link to='/menu/keepalivesnow'>
<button>查看详情页keep-aliva-details</button>
</router-link> -->
<button @click="toList">查看详情页keep-aliva-details</button>
<button @click="getTableList('add1')">获取表格数据</button>
</div>
</div>
</template>
<script setup lang="ts" name="keepalive">
import { useRouter } from "vue-router"
import { useKeepStore } from '@/views/stores/keepalive'
import { getCurrentInstance } from 'vue'
const router = useRouter()
let keepStoreData = useKeepStore()
const KValue = ref('')
// 跳转详情
const toList = ()=>{
keepStoreData.includeArr = ['keepalive']
router.push({
path: '/menu/keepalivesnow'
})
}
// 表格
let tableData = ref([])
let total = ref(2)
let currentPage = ref(1)
const handleCurrentChange = (val:number)=>{
console.log('81',val)
}
// 测试接口
let internalInstance = getCurrentInstance();
let Api = internalInstance && internalInstance.appContext.config.globalProperties.$api
let params = {}
let nameList = ref([])
let getTableList = (add:string)=>{
Api.getVideoList(params).then((res: any)=>{
nameList.value = res.payload || []
tableData.value = res.payload.map((item:any)=>{
return {
name: item,
address: add
}
})
})
}
getTableList('add2')
// keep生命周期
onActivated(() => {
// 调用时机为首次挂载
// 以及每次从缓存中被重新插入时
console.log('a-onActivated')
})
onDeactivated(() => {
// 在从 DOM 上移除、进入缓存
// 以及组件卸载时调用
console.log('a-onDeactivated')
})
</script>
<style scoped lang="less">
.el-input{
width: 300px;
}
.keep-table{
display: flex;
justify-content: center;
}
.keep-pagination{
display: flex;
justify-content: center;
}
</style>
6.6、src/views/keepaliva/snow.vue
<template>
<div class="container">
<div>keep-alive-snow-详情页面</div>
<div>
<span>输入框:</span>
<el-input v-model="KValue"></el-input>
</div>
<div>
<router-link to='/menu/keepalive'>
<button>回到列表页keep-aliva-list</button>
</router-link>
</div>
</div>
</template>
<script setup lang="ts" name="keepalivesnow">
const KValue = ref('')
onActivated(() => {
// 调用时机为首次挂载
// 以及每次从缓存中被重新插入时
console.log('b-onActivated')
})
onDeactivated(() => {
// 在从 DOM 上移除、进入缓存
// 以及组件卸载时调用
console.log('b-onDeactivated')
})
</script>
<style scoped lang="less">
.el-input{
width: 300px;
}
</style>
6.7、页面测试 name为keepalive的组件已被缓存,点击菜单清除缓存获取最新数据,测试成功。
七、onActivated、onDeactivated
onActivated:进入页面
onDeactivated:离开页面
八、C知道
问:vue3 keepalive使用详解
答:
Vue3 中的 keep-alive 组件是用于缓存动态组件的,可以在组件切换时保留组件的状态和避免重新渲染。下面是关于 Vue3 keep-alive 的使用详解:
基本使用
在需要缓存的组件外部包裹一个 <keep-alive> 标签,将需要缓存的组件放在其中:
<template>
<keep-alive>
<router-view />
</keep-alive>
</template>
缓存的组件生命周期钩子函数
当一个组件被缓存时,它的生命周期钩子函数会有所不同。具体如下:
activated: 缓存的组件被激活时调用,可以在这里执行一些需要在组件激活时执行的操作。
deactivated: 缓存的组件被停用时调用,可以在这里执行一些需要在组件停用时执行的操作。
<template>
<keep-alive>
<router-view v-slot="{ Component }">
<component :is="Component" />
</router-view>
</keep-alive>
</template>
在缓存的组件中添加 activated 和 deactivated 钩子函数:
<script>
export default {
name: 'cached-component',
activated() {
console.log('cached-component activated')
},
deactivated() {
console.log('cached-component deactivated')
},
}
</script>
include 和 exclude 属性
include 和 exclude 属性可以用来控制 keep-alive 缓存哪些组件和排除哪些组件。它们都可以传递一个字符串或正则表达式的数组。
include:只有在 include 数组中的组件才会被缓存。
exclude:在 exclude 数组中的组件不会被缓存。
<template>
<keep-alive include="home, about">
<router-view v-slot="{ Component }">
<component :is="Component" />
</router-view>
</keep-alive>
</template>
max 属性
max 属性用于设置缓存的最大组件数,当缓存的组件数量超过最大值时,最早缓存的组件会被销毁。
<template>
<keep-alive max="10">
<router-view v-slot="{ Component }">
<component :is="Component" />
</router-view>
</keep-alive>
</template>
九、相关内容
1、通过url记录列表页的关键信息,查询条件、分页等
2、通过sessionStorage记录列表页的关键信息,查询条件、分页等
session只能在同一个页面起作用,所以复制一个链接打开后,对原来正常的操作的页面没有影响
3、keepalive--本文
十、过程记录
记录一、
Uncaught (in promise) TypeError: parentComponent.ctx.deactivate is not a function
解决:
十一、欢迎交流指正,关注我,一起学习。
参考链接:
vue3中一些简单的小技巧_vite-plugin-vue-setup-extend_还一激灵的博客-CSDN博客
vue3 keep-alive 页面切换不触发onActivated和onDeactivated方法周期_vue3 onactivated_凯扣叮~的博客-CSDN博客
学习Vue3 第二十章(keep-alive缓存组件)_keep-live vue3 activated_小满zs的博客-CSDN博客
Vue3知识点_onactivated_阿信呐的博客-CSDN博客
如何在vue3的jsx中使用keep-alive? - 知乎
https://ask.csdn.net/questions/7727011
https://www.cnblogs.com/lyt0207/p/16543867.html
Vue3 keep-alive 缓存问题_ZL随心的博客-CSDN博客
https://www.cnblogs.com/aehyok/p/16328765.html
https://free_pan.gitee.io/router-tabs-wk/
vue3基于Element Plus和vue-router实现选项卡-多标签组件_哔哩哔哩_bilibili