需求
后台管理系统菜单之间切换要求实现页面缓存,同个页面参数不一样也要缓存(比如同个表单详情页,id不一样), 可以来回切换不刷新里面数据,并且再需要关闭时要删除对应的缓存,再下次打开是要缓存新的页面。
github 地址
首先:
想着使用<keep-alive></keep-alive>来实现,同一路由页参数不一样又要缓存,所以使用 $route.fullPath 作为key, 根据路由meta里面的参数来设置是否需要实现缓存,
再网上找了很多都是只能用<keep-alive></keep-alive>实现缓存,不能实现动态删除的, 这样根本没法使用。
思路:
所以我就想研究了一下vue 的vnode数据存储,找找它把keep-alive保存下来的页面存储再哪, 经过大半天的寻找最后终于找到了。
下面贴主要代码
菜单栏跳转路由方法
左边菜单栏组件 LeftMenu.vue
// 跳转
goRouter(item) {
if (item.children.length > 0) {
item.showSon = !item.showSon;
} else {
if (item.is_click === "2") {
this.$message.warning("近期开放,敬请期待!");
} else {
item.menuType = "child";
this.$store.commit('changeBreadcrumb', item);
this.$router.push({ path: item.URL_LINK });
}
}
},
最主要的store,数据
最主要的func
const state = {
// 打开的tab标签页对象
cacheList: [],
menuList: [],
menuActive: {},
isMenuNodeExist: null,
isMenuExist: null,
fatherMenu: {},
childmenu: {},
isReload: false,
reloadRouter: false,
menuMap: new Map()
};
export default {
state,
mutations: {
// 修改刷新router
initRouter(state){
state.reloadRouter = false;
},
// 更新状态
updateState(state){
state.isReload = !state.isReload;
},
// 加入list
addCacheMenu (state, item) {
state.cacheList.push(item);
this.commit('openCacheMenu', item)
},
// 缓存菜单的键值对
setMenuMap(state, menuMap){
state.menuMap = menuMap;
},
// open Menu
openCacheMenu (state, item) {
state.menuActive = item;
},
// 删除menu
delMenu(state, index){
state.cacheList.splice(index, 1);
},
deleteMenu(state, _this){
let url = _this.$route.fullPath;
let index = state.cacheList.findIndex((item)=>{
return item.fullPath === url;
});
state.reloadRouter = false;
if(index !== -1){
state.cacheList.splice(index, 1);
_this._deleteType = "view";
this.commit('dropCache', _this)
}
},
// 判断Menu是否存在
isMenuExist(state, url){
let isExist = state.cacheList.some((item)=>{
return item.fullPath === url;
});
state.isMenuExist = isExist;
},
isMenuListExist(state, nodeId){
let isExist = state.menuList.some((item)=>{
return item.NODE_ID === nodeId;
});
state.isMenuNodeExist = isExist;
},
// 变更面包屑
changeBreadcrumb(state,item){
if(item.menuType === "child") {
state.childmenu = item;
sessionStorage.setItem("childmenu", JSON.stringify(item));
}
if(item.menuType === "father"){
state.fatherMenu = item;
state.childmenu = {};
sessionStorage.setItem("menu", JSON.stringify(item));
sessionStorage.removeItem("childmenu");
}
this.commit('isMenuListExist', item.NODE_ID);
if (!state.isMenuNodeExist) {
state.menuList.push(item);
}
},
// 变更路由
checkRouterLink(state, item){
let url = item.fullPath;
this.commit('isMenuExist', url);
if (!state.isMenuExist) {
// 该标签当前没有打开
this.commit('addCacheMenu', item)
} else {
// 该标签是已经打开过的,需要激活此标签页
this.commit('openCacheMenu', item)
}
},
// 删除缓存
dropCache(state, _this){
state.reloadRouter = _this.reloadRouter ? _this.reloadRouter : false;
let children = "";
// 页面内的返回或关闭按钮
if(_this._deleteType === "view"){
children = _this;
// 上面cahcheMenu 的关闭
} else {
let cacheList = state.cacheList;
let comIndex = cacheList.length - _this.index;
children = _this.$parent.$children[_this.$parent.$children.length - comIndex - 1];
}
console.log(children.$vnode);
let key = children.$vnode.key;
let cache = children.$vnode.parent.componentInstance.cache;
let keys = children.$vnode.parent.componentInstance.keys;
if (cache[key]){
if (keys.length) {
var index = keys.indexOf(key);
if (index > -1) {
keys.splice(index, 1);
}
}
delete cache[key];
}
children.$destroy();
},
// 初始化所有缓存
clearAllValue(state, item){
state.cacheList = [];
state.menuList = [];
state.menuActive = {};
state.isMenuNodeExist = null;
state.isMenuExist = null;
state.reloadRouter = false;
state.fatherMenu = {};
state.childmenu = {};
sessionStorage.removeItem("menu");
sessionStorage.removeItem("childmenu");
}
},
};
路由配置
AppPage.vue 根据 keepAlive 来判断是否缓存
<keep-alive>
<router-view v-if="$route.meta.keepAlive" :key="$route.fullPath"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive" :key="$route.fullPath"></router-view>
删除缓存快照
后面又要求, 比如新增了某条数据后返回列表,要重新请求一下列表数据(不刷新页面)
改版后 加个参数 true 就是要 重新获取数据(不刷新页面)
更改页
列表页, 监听数据去执行方法
代码已经存放到github 上, 下载下来就可以运行。