不同路由复用同一组件,keepAlive解决方案

1,291 阅读2分钟

场景

管理后台使用tags的形式打开页面,存在不同路由复用同一组件的情况。

原始的keep-alive使用include,是通过path匹配页面组件的name实现,name默认是根据文件名自动生成,include剔除路由时,会把想通name的组件缓存清除,导致已有缓存丢失。

官方未提供api等解决方案,on Aug 15, 2021已有prgithub.com/vuejs/core/…

keep-alive源码位置:github.com/vuejs/core/…

最终选择方案三,暴露keep-alive缓存删除方法。

方案一:

复制keepalive组件重写,使其缓存匹配通过key识别;使用includeKey 识别。
juejin.cn/post/714006…
github.com/meadmin-cn/…

缺点:

全文件复制,文件过多。

不满足特殊场景,如新开页面编辑,回到列表页需要刷新

方案二:

获取keepalive的cache,进行处理集中。非dev环境,未能暴露cache。

在vue.config.js增加配置修改对应文件,暴露__v_cache

www.cnblogs.com/shanfeng100…

const path = require("path");
const fs = require("fs");
try {
  const vue_bundler_file = path.resolve(
    __dirname,
    "node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js"
  );
  //使用同步读取文件
  let data = fs.readFileSync(vue_bundler_file, "utf8");
  //如果未添加过
  if (data.indexOf("//__v_cache") < 0) {
    console.log("正在修改源码文件:", vue_bundler_file);
    //先找到__v_cache变量的位置
    let index = data.indexOf("__v_cache");
    if (index >= 0) {
      // 继续往前找if关键字
      index = data.lastIndexOf("if ", index);
      if (index >= 0) {
        //从上一个位置开始
        index -= 1;
        //然后放一个注释
        const comment = " //__v_cache ";
        //然后拼接
        data = data.substring(0, index) + comment + data.substring(index);

        //继续往后找下一个大括号 }
        index = data.indexOf("}", index);
        if (index >= 0) {
          //从上一个位置开始
          index -= 1;
          //然后拼接
          data = data.substring(0, index) + comment + data.substring(index);
        }

        fs.writeFileSync(vue_bundler_file, data, "utf8");
      }
    }
  }
} catch (er) {
  console.error(er.message);
}
export default {
  setup() {
    const instance = getCurrentInstance();
    const handler = new KeepAliveHandler();
    onMounted(() => {
      const keepAlive = instance.refs.keepAlive;
      handler.bind(keepAlive);
    });
    const remove = (key) => {
      handler.remove(key);
    };

    return {
      remove,
    };
  },
};

方案三:

使keepalive暴露删除方法pruneCacheEntry。使用暴露的删除缓存方法,全缓存情况下,fullPath作为key值,按需处理页面缓存需要。

taglist减少或单独关闭tag页时调用pruneCacheEntry;特殊需要(如编辑),清除对应路由缓存。

vue.config.js增加配置修改对应文件

const path = require("path");
const fs = require("fs");
try {
  const vue_bundler_file = path.resolve(
    __dirname,
    "node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js"
  );
  //使用同步读取文件
  const data = fs.readFileSync(vue_bundler_file, "utf8");
  //如果未添加过
  if (data.indexOf("sharedContext.$pruneCacheEntry") < 0) {
    console.log("正在修改源码文件:", vue_bundler_file);
    //先找到__v_cache变量的位置
    let index = data.indexOf("__v_cache");
    if (index >= 0) {
      // 继续找下一个大括号 }
      index = data.indexOf("}", index);
      if (index >= 0) {
        //从下一个位置开始
        index += 1;
        //然后放一个可以释放的函数
        const remove =
          "        sharedContext.$pruneCacheEntry = (key) => cache.get(key) && pruneCacheEntry(key);";
        //然后拼接
        const result =
          data.substring(0, index) +
          "\r\n" +
          remove +
          "\r\n" +
          data.substring(index);
        fs.writeFileSync(vue_bundler_file, result, "utf8");
      }
    }
  }
} catch (er) {
  console.error(er.message);
}
<router-view #="{ Component, route }">
  <keep-alive ref="keepAlive">
    <component :is="Component" :key="route.fullPath" />
  </keep-alive>
</router-view>
if (this.$refs.keepAlive.$pruneCacheEntry) {
  this.$store.commit('SET_PRUNE', this.$refs.keepAlive.$pruneCacheEntry);
}

遇到问题,本地vite开发,会存在文件构建缓存(.vite/.deps),方法未暴露成功, --fore编译启动可清除构建缓存,或增加production启动后,再恢复。