vue页面缓存keep-alive,可自选是否删除
需求
后台管理系统菜单之间切换要求实现页面缓存,同个页面参数不一样也要缓存(比如同个表单详情页,id不一样), 可以来回切换不刷新里面数据,并且再需要关闭时要删除对应的缓存,再下次打开是要缓存新的页面。
github 地址
https://github.com/wzhGitH/test-menu-cache
首先:
想着使用<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 上, 下载下来就可以运行。