vue手动清除keep-alive中的缓存

当我们在项目中使用tagView切换拦的时候,意味着我们需要缓存出现的页面
在这里插入图片描述

利用keep-alive的include,新打开标签时,把当前组件名加入到include数组里,关闭标签时从数组中删除关闭标签的组件名就可以了

首先,keep-alive组件的include是可以绑定匹配名字的组件,匹配的组件将会被缓存,所以我们可以动态的在vuex里面绑定一个缓存。
在这里插入图片描述
打开的vue调试工具窗口查看vuex里面的值,这里我使用cachedViews去存储vue需要缓存的组件,这个值是组件的name值而不是路由name的值,所以后面会引出一个问题。
在这里插入图片描述
所以点击删除的时候把对应的名字从include里面删除,vue的keep-alive组件内部自动会把对应的组件缓存删掉。

  DEL_CACHED_VIEW: (state, view) => {
    const index = state.cachedViews.indexOf(view.name);
    index > -1 && state.cachedViews.splice(index, 1);
  },
  
  // 直接从cachedViews删掉就是,included绑定就是cachedViews,删掉后keep-alive就会自动删除缓存

但是如果有另外一种情况:不同的页面使用的是同一个组件,如果还是按照上面的逻辑去删除,就会导致删除一个页面的时候把所有使用该组件的页面的缓存给删除。
在这里插入图片描述
这样肯定不是我们想要的。所以我们需要删除点击的那个组件实例去删除,很遗憾官网没有提供直接删除某一个组件实例的方法。

所以只有从keep-alive存储缓存的源码出手,把组件的实例删除掉。
在这里插入图片描述
在vue的源码里面就是sess去控制缓存的,缓存了一个实例对象,所以我们需要把这个实例对象给删掉,这样才能清楚缓存。

function remove(arr, item) {
  if (arr.length) {
    const index = arr.indexOf(item);
    if (index > -1) {
      return arr.splice(index, 1);
    }
  }
}
/**
 * 清除缓存和实例
 * @param { VNodeCache } cache
 * @param { string } key
 * @param { Array<string> } keys
 * @param { VNode } current
 */
function pruneCacheEntry(cache, key, keys, current) {
  var cachedItem = cache[key];
  if (cachedItem && (!current || cachedItem.tag !== current.tag)) {
    cachedItem.componentInstance.$destroy();
  }
  cache[key] = null;
  remove(keys, key);
}

// 参考问题:https://github.com/vuejs/vue/issues/6509
/**
 * 清除keep-alive中某个组件的缓存,逻辑参考 keep-alive 的源码实现
 * @param { VNode } instance 需要清除的组件的实例对象,这个组件应为 keep-alive 的直接子组件
 * @returns
 */
export default function clearAliveCache(instance) {
  const attributesRequired = instance.$vnode &&
        instance.$vnode.data.keepAlive &&
        instance.$vnode.parent &&
        instance.$vnode.parent.componentInstance &&
        instance.$vnode.parent.componentInstance.cache &&
        instance.$vnode.componentOptions;

  if (!attributesRequired) {
    return false;
  }

  const tag = instance.$vnode.componentOptions.tag ? "::" + instance.$vnode.componentOptions.tag : "";
  const key = !instance.$vnode.key ? instance.$vnode.componentOptions.Ctor.cid + tag : instance.$vnode.key;
  // 拿到该实例对象父组件的组件对象,通过父组件去删除子组件。
  const { cache, keys, $vnode } = instance.$vnode.parent.componentInstance;
  if (cache[key]) {
    pruneCacheEntry(cache, key, keys, $vnode);
  }
}```
有了**clearAliveCache**方法就可以强制性的从vue的缓存中删除去掉的选中的实例的缓存;

但是怎么拿到该组件的实例对象呢?

我这里是把Vue实例保存在state里面:**mainComp**
![在这里插入图片描述](https://img-blog.csdnimg.cn/db9b585521764598b961f9680b4b3cdc.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAYmFpZHVfNDE2Nzc4ODc=,size_20,color_FFFFFF,t_70,g_se,x_16)
然后就可以在点击的时候通过mainComp.$children 拿到所有的对象,我这里还创建了一个数组去存储路由对象用于tagView组件的展示。
![在这里插入图片描述](https://img-blog.csdnimg.cn/57e8e5df0893484c831aad35e71cdf7b.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAYmFpZHVfNDE2Nzc4ODc=,size_14,color_FFFFFF,t_70,g_se,x_16)
里面的元素就是一个路由对象,因为如果不同的页面使用的同一个组件,就需要额外的判断条件了,这里我用的就是路由对象的key和组件对象的key相等吧实例对象给取出来然后删掉的。
![在这里插入图片描述](https://img-blog.csdnimg.cn/a16a563c33334d71b6bac5a266847102.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAYmFpZHVfNDE2Nzc4ODc=,size_19,color_FFFFFF,t_70,g_se,x_16)
github讨论区:https://github.com/vuejs/vue/issues/6509

版权声明:本文为baidu_41677887原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。