需求
列表页上每个Row上都有【编辑】功能,点击进去就是详情页(有表单编辑的需求)
<el-table-column label="查看详情">
<template v-slot="{ row }">
<el-link
@click="$router.push({name: 'info', query: { id: row.id }})"
type="primary">查看详情</el-link>
</template>
</el-table-column>
keep-alive实现
- vuex保存顶部路由消息
const keepRouter = {
state: {
router: [],
},
mutations: {
addRouter(state, router) {
// 可同时存在: 仅校验path(router-link :key=item.path)
const index = state.router.findIndex((item) => item.path === router.path);
if (index === -1) {
state.router.push(router);
}
},
removeRouter(state, index) {
const { router } = state;
router.splice(index, 1);
state.router = router;
},
},
}
- router使用beforeEnter,将路由信息保存到vuex里
import store from './store';
const routes = [
...,
{
path: '/info',
name: 'info',
component: infoCom,
meta: { title: 'info' },
beforeEnter: function (to, from, next) {
store.commit('addRouter', {
title: to.meta.title,
name: to.name,
path: to.fullPath,
});
next();
},
}
]
- keep-alive的父级组件上展示vuex的信息
computed: {
list() {
return this.$store.state.keepRouter.router;
},
},
<router-link
v-for="(item, index) in list"
:key="item.path"
:to="{path: item.path}"
:active-class="$style.action"
exact>
<span>{{ item.title }}</span>
<i
v-if="list.length > 1"
@click.prevent="remove(index, item)"
class="el-icon-close"></i>
</router-link>
- keep-alive上设置exclude参数(router-view必须具有key)
data() {
return {
exclude: [],
};
},
<keep-alive :exclude="exclude">
<router-view :key="$route.fullPath"></router-view>
</keep-alive>
- 关闭的页面设置exclue,半秒后还原
methods: {
...,
remove(index, route) {
if (route.path === this.$route.fullPath) {
// 加载上一路由或下一个路由
const toPath = this.list[index === 0 ? 1 : index - 1].path;
this.$router.push({ path: toPath });
}
this.setExclude([route.name]);
this.$store.commit('removeRouter', index);
},
setExclude(name) {
// 可消除对应组件的缓存
this.exclude = name;
setTimeout(() => {
this.exclude = [];
}, 500);
},
},
问题
总结:匹配规则是组件的name
这时在上面需求中就会出现问题,因为即便2个url不一样的详情页面name="info",用到的详情组件是一样的。只是url不同,获取到的详情页数据也不同。这时设置的exclude属性会将这个组件销毁,即便它url不一样。
另辟蹊径
通过exclude了解到,它会将name="info"的组件都销毁,那么我们在销毁时保存不需要销毁页面的数据呢
- vuex增加缓存功能
const keepRouter = {
state: {
router: [],
destroyPath: '', // 关闭的页面
cache: {}, // 缓存数据
},
mutations: {
addRouter(state, router) { ... },
removeRouter(state, index) { ... },
// 新增
addCache(state, { key, cache }) {
state.cache[key] = cache;
},
removeCache(state, key) {
const { cache } = state;
delete cache[key];
state.cache = cache;
},
setDestroyPath(state, fullPath) {
state.destroyPath = fullPath;
// 一次性关闭多个同组件时,删除缓存
state.cache[fullPath] && this.commit('removeCache', fullPath);
},
}
- 保存需要关闭页面的路径
remove(index, route) {
this.$store.commit('setDestroyPath', route.path); // 保存关闭的路径
if (route.path === this.$route.fullPath) {
const toPath = this.list[index === 0 ? 1 : index - 1].path;
this.$router.push({ path: toPath });
}
this.setExclude([route.name]);
this.$store.commit('removeRouter', index);
},
- 详情页的处理(这里可以做成mixin,引入到需要的组件上)
info组件
export default {
name: 'info',
data() {
return {
currentPath: '',
form: {
xxx: '',
yyy: '',
zzz: '',
},
};
},
created() {
const { fullPath } = this.$route;
this.currentPath = fullPath;
const cache = this.$store.state.keepRouter.cache[fullPath];
// 是否有缓存
if (cache) {
this.$store.commit('removeCache', fullPath);
Object.keys(cache).forEach((key) => {
this[key] = cache[key];
});
} else {
// 请求详情数据
...
}
},
beforeDestroy() {
const { currentPath } = this;
if (currentPath !== this.$store.state.keepRouter.destroyPath) {
this.$store.commit('addCache', {
key: currentPath,
cache: JSON.parse(JSON.stringify(this.$data)),
});
}
},
};
</script>
注:因为关闭页面时fullPath是未知了,可能会在list页面上就关闭info页面,所以必须保存fullpath
注意事项
- keepRouter保存的路由信息是router里的name,exclude是组件的name,所以这里必须一致
结语
这只是我的一个解题思路,希望有更好的解决方案