vue keepAlive组件大家都不陌生,用于对组件进行缓存(离开路由不会销毁组件),它有以下props
Props:
include- 字符串或正则表达式。只有名称匹配的组件会被缓存。exclude- 字符串或正则表达式。任何名称匹配的组件都不会被缓存。max- 数字。最多可以缓存多少组件实例。
可以利用上面prop对组件进行缓存或不缓存、但在实际开发过程中可能会遇到以下需求
需求:
A界面=>B界面 (期望B界面是新生成的)B界面=>C界面 (对B界面进行缓存)C界面回退=>B界面(恢复缓存)
问题分析
- 如果对
B界面设置keepalive缓存,则A界面=>B界面会读之前的缓存,不满足需求1。 - 如果
B界面不设置缓存,在C界面回退=>B界面会重新生成界面,不满足需求3。
解决方法(动态缓存)
使用动态缓存则需要在组件和路由配置中设置name属性(两者需保持一致),因为vue会根据name属性作为是否缓存依据
- 使用
keep-alive的include属性对组件进行缓存。 - 使用
vuex管理需要缓存的组件name属性数组。
//根组件
<keep-alive :include="cachedViews" :max="15">
<router-view :key="key" />
</keep-alive>
// script
computed: {
cachedViews () {
return this.$store.state.cachedViews.cachedViews
},
key () {
return this.$route.path
},
},
// 监听路由变化,为keepAlive:true 的路由自动添加到缓存数组
watch: {
$route: {
immediate: true,
handler (route) {
const { name, meta: { keepAlive } } = route
if (name && keepAlive) {
this.$store.commit('cachedViews/ADD_CACHED_VIEW', route)
}
},
},
},
3.新建一个vuex模块cachedViews.js,cachedViews数组包含缓存的组件name属性。
const state = {
cachedViews: [], // 示例 ['TemplateB', 'TemplateC']
}
const mutations = {
// 添加缓存
ADD_CACHED_VIEW: (state, view) => {
if (state.cachedViews.includes(view.name)) {
return
}
state.cachedViews.push(view.name)
},
// 移除缓存
DEL_CACHED_VIEW: (state, view) => {
const index = state.cachedViews.indexOf(view.name)
index > -1 && state.cachedViews.splice(index, 1)
},
}
export default {
//开启命名模块
namespaced: true,
state,
mutations,
}
- Store中引入。
import Vue from 'vue'
import Vuex from 'vuex'
import cachedViews from './cachedViews'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
modules: {
cachedViews,
},
})
- 将
B界面设置缓存( keepAlive: true)。
{
name: 'order', // 此处name必须与组件内的name属性一致 export default { name:'order'}
path: '/order',
component: () => import('../views/me/order/index'),
meta: { title: '我的订单', keepAlive: true },
},
- 在
B界面使用beforeRouteLeave组件路由守卫,解决从A界面=>B界面(需求1)有缓存的问题。
// 官方路由介绍
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
- 在离开当前路由时调用
DEL_CACHED_VIEW方法从缓存列表中移除。
beforeRouteLeave (to, from, next) {
// 去这些界面我需要缓存
const routerArr = ['/TemplateC', '/TemplateD']
if (!routerArr.includes(to.path)) {
// 不在缓存列表中,从cachedViews缓存列表中移除
this.$store.commit('cachedViews/DEL_CACHED_VIEW', form)
}
next()
},
至此我们就解决了动态缓存的问题啦!
总结
- 利用
include可以实现对组件是否缓存。 - 利用
vuex对缓存组件的name属性进行动态管理。 beforeRouteLeave组件路由守卫,动态移除缓存。