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 上, 下载下来就可以运行。

 

posted @ 2022-06-01 11:13  neeol的博客  阅读(243)  评论(0编辑  收藏  举报