1.实现效果
keep-alive.gif
2.keep-alive
2.1是什么:
keep-alive 是 Vue 的内置组件,keep-alive 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 transition 相似,keep-alive是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。
2.2做什么:
在组件切换过程中将状态保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性。主要用于保留组件状态或避免重新渲染。比如:列表进详情页面,面包屑跳转页面等。
2.3怎么用:
1.基本用法
<!-- 基本 -->
<keep-alive>
<component :is="view"></component>
</keep-alive>
<!-- 多个条件判断的子组件 -->
<keep-alive>
<comp-a v-if="a > 1"></comp-a>
<comp-b v-else></comp-b>
</keep-alive>
<!-- 和 `<transition>` 一起使用 -->
<transition>
<keep-alive>
<component :is="view"></component>
</keep-alive>
</transition>
2.当组件在 keep-alive 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。
- activated:在 keep-alive 组件激活时调用,服务器端渲染期间不被调用。在被缓存页面可以替代created更新数据。
- deactivated:在 keep-alive 组件停用时调用,服务器端渲染期间不被调用。
3.Props:
include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例。
include 和 exclude prop 允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示:
<!-- 逗号分隔字符串 -->
<keep-alive include="a,b">
<component :is="view"></component>
</keep-alive>
<!-- 正则表达式 (使用 `v-bind`) -->
<keep-alive :include="/a|b/">
<component :is="view"></component>
</keep-alive>
<!-- 数组 (使用 `v-bind`) -->
<keep-alive :include="['a', 'b']">
<component :is="view"></component>
</keep-alive>
匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值)。匿名组件不能被匹配。
4.项目中的一些用法
- 路由元信息中的keepAlive判断是否缓存
<!-- 结合路由一起使用 -->
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
- 路由钩子中动态设置keepAlive
beforeRouteLeave (to, from, next) {
if (to.path === 'xxx') {
from.meta.keepAlive = true
} else {
from.meta.keepAlive = false
}
next()
},
- vuex+include动态缓存组件
3.实现步骤
方法一.vuex+include
为每个页面设置不重复的name字段,当点击菜单栏的时候,将点击的组件的name值存入catch_components中,当点击关闭标签时,删除该项。
<keep-alive :include="catch_components" :max="10">
<router-view></router-view>
</keep-alive>
index.vue:
computed:{
...mapState({
catch_components: (state) => state.catch_components, // keepalive缓存
}),
}
//点击选中某菜单
selectMenu(item, i, subName) {
// 方法一:利用include
this.$store.commit("addKeepAliveCache", item.name);
var submenu = {
path: item.path,
name: item.name,
label: item.title,
index: i,
subName: subName,
};
this.$store.commit("selectMenu", submenu);
this.$router.push({ path: item.path });
},
//关闭某个菜单
handleClose(tab, index) {
// 删除keepAlive缓存
// 方法一:利用include
this.$store.commit("removeKeepAliveCache", tab.name);
},
vuex:
// 添加keepalive缓存
addKeepAliveCache(state, val) {
if (val === '/homepage') {
return;
}
if (state.catch_components.indexOf(val) === -1) {
state.catch_components.push(val);
}
},
// 删除keepalive缓存
removeKeepAliveCache(state, val) {
let cache = state.catch_components;
for (let i = 0; i < cache.length; i++) {
if (cache[i] === val) {
cache.splice(i, 1);
}
}
state.catch_components = cache;
},
方法2.vuex+暴力删除cache和keys
无需设置页面的name字段,当点击菜单栏的时候,将点击的组件的路径值存入catch_components中,当关闭按钮时候,删除该路径,并找到当前已缓存的cache和keys,暴力删除该缓存页面。
<keep-alive :max="10">
<router-view
:key="$route.path"
v-if="catch_components.includes(this.$route.path)"
></router-view>
</keep-alive>
<router-view
:key="$route.path"
v-if="!catch_components.includes(this.$route.path)"
></router-view>
如何拿到当前已缓存的cache和keys
- 路由钩子函数中获取(此方法只能是关闭当前路由页面才能获取到)
beforeRouteLeave(to, from, next) {
let cache = this.$vnode.parent.componentInstance.cache; //缓存的组件路径
let keys = this.$vnode.parent.componentInstance.keys; // 缓存的组件key值
next()
},
- computed中获取(这个方法可以监听到当前页面离开或点击关闭按钮离开)
cache: {
get() {
if (!this.$route.matched[1]) return;
const instances = this.$route.matched[1].instances;
return instances && instances.default && instances.default.$vnode
? instances.default.$vnode.parent.componentInstance.cache
: {};
},
set(val) {
this.$route.matched[1].instances.default.$vnode.parent.componentInstance.cache =
val;
},
},
cache_key: {
get() {
if (!this.$route.matched[1]) return;
const instances = this.$route.matched[1].instances;
return instances && instances.default && instances.default.$vnode
? instances.default.$vnode.parent.componentInstance.keys
: [];
},
set(val) {
this.$route.matched[1].instances.default.$vnode.parent.componentInstance.keys =
val;
},
},
index.vue
//当关闭tab标签时候,删除指定缓存
handleClose(tab, index) {
// console.log("缓存-------------------------------", this.cache);
// console.log("keys---------------------------------", this.cache_key);
let cache = this.cache,
keys = this.cache_key;
if (cache[tab.path] != null) {
delete cache[tab.path];
keys.splice(keys.indexOf(tab.path), 1);
}
// 删除keepAlive缓存
// 方法二:利用path
this.$store.commit("removeKeepAliveCache", tab.path);
},