背景:将tab页面缓存,例如A页面输入123,通过tab标签跳转到B页面,再点击A标签,跳转回A页面,这时需要保留输入的123 。本来,直接使用keep-alive就行了,但是这几个路由绑定的是同一个页面。。。。。。
- 多个路由绑定同一个页面路由配置
{ path: '/A', name: 'A', component: CommonPage },
{ path: '/B', name: 'B', component: CommonPage },
{ path: '/C', name: 'C',component: CommonPage },
{ path: '/D', name: 'D',component: CommonPage },
- 为什么不能直接使用keep-alive(个人理解)
因为keep-alive是默认根据.vue文件的export default { name: 'StaStationPage',
name属性来进行页面缓存的,但是多个路由指向同一个页面,那对于keep-alive来说,就只有一个对象,所以只会缓存一份。
解决方案
- 不使用.vue文件的name属性,改用路由地址path,或路由名称name,这种比较唯一性的值作为keep-alive缓存条件,以下是自定义的keep-alive组件代码myKeepAlive.vue
<script>
function isEmpty(...str) {
return str.some((i) => i === undefined || i === null || i === "");
}
function getFirstComponentChild(children) {
if (Array.isArray(children)) {
return children.find(
(c) =>
!isEmpty(c) &&
(!isEmpty(c.componentOptions) || (c.isComment && c.asyncFactory))
);
}
}
function removeCache(cache, key) {
const cached = cache[key];
cached && cached.componentInstance && cached.componentInstance.$destroy();
delete cache[key];
}
function getRouterViewCacheKey(route) {
// 建议使用route配置的那些属性作为key,例如path、name等
return route.path
}
export default {
name: "my-keep-alive",
abstract: true,
props: {include: Array},
created() {
this.cache = Object.create(null);
},
beforeDestroy() {
for (const key of Object.keys(this.cache)) {
removeCache(this.cache, key);
}
},
render() {
const slot = this.$slots.default;
const vnode = getFirstComponentChild(slot);
let componentOptions = vnode && vnode.componentOptions;
if (componentOptions) {
const child =
componentOptions.tag === "transition"
? componentOptions.children[0]
: vnode;
componentOptions = child && child.componentOptions;
if (componentOptions) {
const key = getRouterViewCacheKey(this.$route)
const { cache,include } = this;
if (include && !include.includes(key)) {
console.log('不含有缓存返回',include,key)
return vnode
}
if (cache[key]) {
child.componentInstance = cache[key].componentInstance;
} else {
cache[key] = child;
}
child.data.keepAlive = true;
}
}
return vnode || (slot && slot[0]);
},
};
</script>
- 添加中转页面,使得第一次进入该路由时,触发created,重新进入生命周期,实现第一次加载,第二次缓存的效果
路由配置如下
{
path: "/redirect",
name: "Redirect",
component: Redirect,
children: [
{
path: '*',
component: Redirect,
meta: {
cantCheck: true
}
}
]
},
Redirect.vue页面代码如下:
<script>
function replaceAll(str, substr, replacement) {
if (str == null) return str
return str.replace(new RegExp(substr, 'gm'), replacement)
}
export default {
mounted() {
console.info('this.$route', this.$route)
const {fullPath} = this.$route
this.$router.replace(`${replaceAll(fullPath, '/redirect', '')}`)
},
render: h => h()
}
</script>
路由守卫permission.js,在路由跳转前,跳转到中转页面,再由中转页面跳到目标页面
// 通过title,判断是否使用通过一个页面,并决定是否跳转到中转页
if (to.meta.title !== undefined && to.meta.title === from.meta.title) {
next(`/redirect${to.fullPath}`);
} else {
next();
}
原有路由配置新增meta参数,修改为如下配置
{ path: '/A', name: 'A', meta: {title: 'onePage'}, component: CommonPage },
{ path: '/B', name: 'B', meta: {title: 'onePage'}, component: CommonPage },
{ path: '/C', name: 'C', meta: {title: 'onePage'}, component: CommonPage },
{ path: '/D', name: 'D', meta: {title: 'onePage'}, component: CommonPage },
至此,学习笔记记录