vue3.x + vue router4.x 缓存方案

需求1:
pageA -> pageB -> pageC
缓存pageB:
pageA进入pageB,刷新页面并缓存页面;
pageC返回pageB,不刷新页面

  1. 在 vuex(或其他存储方案) 声明两个数组
{
    state: () => ({
        keepAliveViews: [],
        notAliveViews: [],
    }),

    mutations: {
        /**
         * 记录需要缓存的路由视图
         */
        saveKeepAliveViews(state, { keepAliveViews }) {
          state.keepAliveViews = keepAliveViews;
        },

        /**
         * 清除页面缓存
         */
        clearCacheView(state, { notAliveViews }) {
          state.notAliveViews = notAliveViews;
        },
    },
}
  1. 在定义路由时,在meta中添加属性keepAlive:true
{
    name: "pageB",
    path: "page-b",
    component: () => import("***/pageB.vue"),
    meta: {
        keepAlive: true,
    },
},
  1. 在适当位置遍历路由表,记录需要缓存的路由的组件名称
// 记录需缓存的路由/组件
const keepAliveViews = [];
router.getRoutes().forEach((routeItem) => {
    if (routeItem?.meta?.keepAlive) {
        // 组件name和路由name保持一致, 所以可以直接使用routeItem.name
        // 也可以在 meta 中添加属性 compName 来用,或其他方案
        keepAliveViews.push(routeItem.name);
    }
});
store.commit("saveKeepAliveViews", { keepAliveViews });
  1. 在路由根组件中
//  template
<router-view v-slot="{ Component }">
    <keep-alive :include="keepAliveViews" :exclude="notAliveViews">
        <component :is="Component" />
    </keep-alive>
</router-view>
// js
const keepAliveViews = computed(() => store.state.keepAliveViews);
const notAliveViews = computed(() => store.state.notAliveViews);

keep-alive会缓存include中存在的组件,会清除exclude中的组件缓存;

  1. 手动清除组件缓存
/**
 * 清除路由(组件/页面)缓存
 */
export function clearCacheView(destroyCompNames) {
  store.commit("clearCacheView", { notAliveViews: destroyCompNames });

  // 清除缓存后,要重置数组为空,下次才能再次缓存
  // 实际上不知道什么时候会完成缓存的清除,这里取500ms,一般满足需求
  setTimeout(() => {
    store.commit("clearCacheView", { notAliveViews: [] });
  }, 500);
}
{
    name: "pageA",
    path: "page-a",
    component: () => import("***/pageA.vue"),
    meta: {},
    beforeEnter: () => {
      clearCacheView(["pageB"]); // 这里的"pageB"是页面pageB的组件名称
    },

返回pageA时,手动清除pageB的缓存;

需求2:
使用缓存页面,大多数都是列表页进入详情页,所以还需要考虑列表页的滚动位置的问题.
即:pageC返回pageB时,pageB要保持在离开时的位置

  1. 在 vuex(或其他存储方案) 声明一个数组
{
    state() {
        return {
            keepAliveViewsScrollPostion: [],
        };
    },

    mutations: {
        // 设置缓存页面滚动元素的位置
        setkeepAliveViewsScrollPostion(state, { routeName, list }) {
            const item = state.keepAliveViewsScrollPostion.find((t) => t.routeName === routeName);
            if (!item) {
                state.keepAliveViewsScrollPostion.push({ routeName, list });
            } else {
                item.list = list;
            }
        },
    },
}
  1. 在定义路由时,在meta中添加属性scrollEls
{
    name: "pageB",
    path: "page-b",
    component: () => import("***/pageB.vue"),
    meta: {
      keepAlive: true,
      scrollEls: [".scroll-list"], // 数组形式,可添加多个可滚动元素
    },
},
  1. 在路由守卫中
/**
 * 全局前置守卫
 */
router.beforeEach((to, from) => {
  // 缓存页面:记录滚动位置
  if (from.meta.scrollEls) {
    const scrollObj: any = { routeName: from.name, list: [] };
    from.meta.scrollEls.forEach((element) => {
      const el = document.querySelector(element);
      if (el) {
        scrollObj.list.push({
          el: element,
          top: el.scrollTop,
        });
      }
    });
    store.commit("setkeepAliveViewsScrollPostion", scrollObj);
  }
});


/**
 * 全局后置钩子
 */
router.afterEach((to, from) => {
  // 缓存页面:滚动到指定位置
  nextTick(() => {
    if (to.meta.scrollEls) {
      const item = store.state.keepAliveViewsScrollPostion.find((t) => t.routeName === to.name);
      if (!item) return;
      item.list.forEach((item2) => {
        const el = document.querySelector(item2.el);
        if (el) {
          el.scrollTop = item2.top;
          item2.top = 0;
        }
      });
      // 使用后重置滚动位置为0
      store.commit("setkeepAliveViewsScrollPostion", item);
    }
  });
});
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1. 一个200*200的div在不同分辨率屏幕上下左右居中,用css实现 2. 写一个左中右布局占满屏幕,其中左...
    造了个轮子阅读 620评论 0 1
  • 本文目录 1.简述Vue的响应式原理 2.delete和Vue.delete删除数组的区别 3.v-for循环时为...
    前端辉羽阅读 985评论 0 12
  • 一、概念介绍 Vue.js和React.js分别是目前国内和国外最火的前端框架,框架跟类库/插件不同,框架是一套完...
    刘远舟阅读 1,089评论 0 0
  • 安装 vue-router 的两种模式 一、hash模式 后面的hash值变化,并不会导致浏览器向服务器发出请求,...
    cesiuming阅读 461评论 0 0
  • 一、父子组件传值 基本概念在Vue中,父子组件间的数据流向可以总结为prop向下传递,事件向上传递,即父组件通过p...
    北风吹_yfy阅读 3,056评论 0 5