共计 2149 个字符,预计需要花费 6 分钟才能阅读完成。
作者:waker
前言
业务里常常有这样的需要, 页面跳转的时候放弃前一个页面的状态跟数据, 不便返回时解决
例如: A->B 须要缓存, A->C 不须要缓存
网上大部分例子都须要去解决业务组件, 感到十分不合理
故本人分享改性能用来解决此类问题
vue 的 keepAlive 组件很适宜解决这类问题, 但还是有缺点, 比方很难灵便的依据路由来管制是否须要缓存, 只能简略的通过 include 来匹配是否须要缓存
整顿后需要如下:
1. 组件须要在局部页面缓存, 脱离了这部分页面则清理缓存 | |
2. 组件须要在全局缓存 | |
3. 最好从架构层面解决, 不要干预业务组件 |
大抵思路
在路由 meta 里增加 keealive:[‘ 路由的 name’], 确定失效的作用页面
设置一个 store 来绑定 keepalive
在全局路由钩子里对该 store 解决
代码如下
路由 meta 里设置 keepAlive, 示意拜访这些页面须要缓存组件
// 路由配置 | |
{ | |
path: 'xxx', | |
name: 'xxx', | |
component: () => import('xxx'), | |
meta: { | |
title: 'xxx', | |
keepAlive: ['路由 name', 'b'],// 作用域: 缓存在这些页面留存 | |
}, | |
}, |
在 store 里设置 keepAliveIncludes 用来绑定 keepAlive
// vuex 设置跟删除缓存组件 | |
state: {keepAliveIncludes:[] | |
}, | |
mutations: { | |
// 设置缓存 | |
SET_KEEPALIVEINCLUDES: (state, data) => {const has = state.keepAliveIncludes.find(i=>i.path === data.path) | |
if(!has){state.keepAliveIncludes.push(data) | |
} | |
}, | |
// 删除缓存 | |
DELETE_KEEPALIVEINCLUDES:(state, data) => {state.keepAliveIncludes = state.keepAliveIncludes.filter(i=>i.always) | |
} | |
}, |
// 业务页面, 应用 keepAlive 的组件 | |
<template> | |
<keep-alive :include="keepAliveIncludes" > | |
<router-view ref="content"/> | |
</keep-alive> | |
</template> | |
<script> | |
export default { | |
computed: {'keepAliveIncludes'() {const arr = this.$store.state.keepAliveIncludes.map(i=>i.componentName) | |
return Array.from(new Set(arr)) | |
}, | |
} | |
</script> |
这样就将 keepAliveIncludes 跟 keepalive 组件绑定了
因为 keepAlive 组件外部对 include 做了订阅, 所以咱们不必思考怎么删除已有缓存, 只须要对 keepAliveIncludes 这个值解决, 组件外部会帮咱们删除
通过全局路由钩子解决 keepAliveIncludes
// 路由钩子 | |
router.beforeEach((to, from, next) => { | |
// 将所有缓存页面的 keepalive 拿进去扁平化 | |
let cachePath = store.state.keepAliveIncludes.map(i => i.keepAlive).flat(Infinity) | |
// 去了不缓存的页面就清理所有十分驻缓存组件 | |
if (!cachePath.includes(to.name)) {// console.log('去了不缓存的页面'); | |
store.commit('DELETE_KEEPALIVEINCLUDES') | |
} | |
if (to.meta.keepAlive) {// const componentsName = to.matched[to.matched.length-1].components.default.name | |
store.commit('SET_KEEPALIVEINCLUDES', {path: `${to.name}`, | |
componentName: to.name, // 要求路由 name 跟默认组件的 name 保持一致 | |
always: to.meta.keepAlive.length === 0, | |
keepAlive: to.meta.keepAlive, | |
}) | |
} | |
}) |
过程
先开始的执行执行思路如下:
线判断是否匹配, 匹配就缓存组件
然而发现,keepAlive 缓存的办法先于 router.beforeEach 执行, 失败
起初换了思路
先缓存组件, 而后在看是否匹配, 不匹配就删除已有缓存
附录
此性能还是有缺点的
该办法须要默认路由组件 name 跟路由列表的 name 保持一致
因为 keepAlive 的 include 指令接管的值是组件 name, 而咱们应用的是异步载入组件, 所以在 router.beforeEach 时, 组件还没有实例化, 没方法拿到组件的 name
当然如果是同步加载组件能够用下列代码拿到组件的 name
to.matched[to.matched.length-1].components.default.name
如果有大佬晓得如何解决欢送留言探讨