vue keepAlive 缓存指定页面

212 阅读1分钟

vue 利用 keepAlive 达到 a页面进入b页面缓存,但是进入c页面不会缓存该a页面

  • 创建一个 mixins 文件,完成该页面功能
  • 注意:
    • 初始化事件不能再放置在created 、mounted 事件中了,需要自己写一个init事件
    • bug: 进入详情页再进入其他页面,重新进入该页面,该页面状态依旧被保存,执行 onSearch 事件
    • 优化: 强制清除该页面得keepAlive缓存(如果你不需要出去页面清除缓存,并且可以存在多个keepAlive页面,只是做进入该页面得刷新,可以删除 beforeRouteLeave 路由守卫)
export default {
  data() {
    return {
      isFirstEntry: true,
      // 离开该组件keepAlive状态存在的页面路径
      isKeepAliveRouterList: [],
    };
  },

  created() {},

  activated() {
    // 如果指定页面返回,并且是页面指定状态,马上重新按照条件查询一次
    if (this.$route.meta.isBack) {
      if (this.isFirstEntry) {
        this.isFirstEntry = false;
        this.init();
      } else this.onSearch();
    } else {
      // 第一次和非详情页进入页面时 isBack都为false,即需要重新请求数据
      if (this.isFirstEntry) this.isFirstEntry = false;
      this.init();
    }
  },

  methods: {
    init() {
      console.log(
        "页面初次进入刷新所有数据,如果该提示存在,你的页面不存在init函数!"
      );
    },
    onSearch() {
      console.log(
        "详情页跳回该页面,如果该提示存在,你的页面不存在onSearch函数,查看页面是否需要按照当前条件刷新!"
      );
    },
    // 获取可以缓存的路径数组
    setIsKeepAliveRouterList(routeMeta, that) {
      let isKeepAliveRouterList = [];
      if (
        routeMeta.isKeepAliveRouterList &&
        Array.isArray(routeMeta.isKeepAliveRouterList)
      ) {
        isKeepAliveRouterList = [
          ...routeMeta.isKeepAliveRouterList,
          ...that.isKeepAliveRouterList,
        ];
      } else {
        isKeepAliveRouterList = [...that.isKeepAliveRouterList];
      }
      return isKeepAliveRouterList;
    },
    // 手动控制keepAlive的强制清除缓存功能
    removeKeepAliveCacheForVueInstance(vueInstance) {
      // 获取当前组件的key值
      let key =
        vueInstance.$vnode.key ??
        vueInstance.$vnode.componentOptions.Ctor.cid +
          (vueInstance.$vnode.componentOptions.tag
            ? `::${vueInstance.$vnode.componentOptions.tag}`
            : "");
      // vueInstance.$vnode.key !== null && vueInstance.$vnode.key !== undefined
      //  ? vueInstance.$vnode.key
      //  : vueInstance.$vnode.componentOptions.Ctor.cid +
      //    (vueInstance.$vnode.componentOptions.tag ? `::${vueInstance.$vnode.componentOptions.tag}` : '');

      // 拿到keep-alive的cache,向上取一层拿到keep-alive的cache
      let cache = vueInstance.$vnode.parent.componentInstance.cache;
      // 拿到keep-alive的keys
      let keys = vueInstance.$vnode.parent.componentInstance.keys;
      if (cache[key]) {
        // 缓存删除了,顺便也让当前组件销毁
        vueInstance.$destroy();
        delete cache[key];
        let index = keys.indexOf(key);
        if (index > -1) {
          keys.splice(index, 1);
        }
      }
    },
  },

  // 导航进入该组件
  beforeRouteEnter(to, from, next) {
    next((vm) => {
      let isKeepAliveRouterList = vm.setIsKeepAliveRouterList(to.meta, vm);

      if (isKeepAliveRouterList.includes(from.path)) {
        to.meta.isBack = true;
      } else {
        to.meta.isBack = false;
      }
    });
  },

  // 导航离开该组件的对应路由时调用
  beforeRouteLeave(to, from, next) {
    let isKeepAliveRouterList = this.setIsKeepAliveRouterList(from.meta, this);

    if (!isKeepAliveRouterList.includes(to.path)) {
      // 退出到非指定页面,清除该keepAlive缓存
      this.isFirstEntry = true;
      this.removeKeepAliveCacheForVueInstance(this);
      // 退出到非指定页面,销毁页面,该方法没有清除缓存,可能会导致页面销毁了,但是keepalive依旧存在缓存
      // this.$destroy();
      // this.$el.parentNode.removeChild(this.$el);
    }

    next();
  },
};
  • route.js 文件中配置路由信息
export default [
	{
		path: '/a',
		name: 'A',
		component: () => import('@/a'),
		// 用于在keepAlive中控制当前页面需要缓存,并且配置了 进入指定路径页面可缓存得数组
		meta: { keepAlive: true, isBack: false, isKeepAliveRouterList: ['/b'] }
	}
]
  • router-view 配置
// max: 最大可keepAlive的页面数量
<keep-alive max="1" >
	<router-view v-if="this.$route.meta.keepAlive" :key="$route.path"/>
</keep-alive>
 <router-view v-if="!this.$route.meta.keepAlive" />