美文网首页
vue3.x + vue router4.x 缓存方案

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

作者: 无疆wj | 来源:发表于2022-05-27 15:25 被阅读0次

需求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);
    }
  });
});

相关文章

网友评论

      本文标题:vue3.x + vue router4.x 缓存方案

      本文链接:https://www.haomeiwen.com/subject/jlgmprtx.html