vue实现页面动态缓存

535 阅读2分钟

实现代码

在进行vue项目开发中,会遇到一些关于页面缓存的 需求 比如:

  • a、b、c 三个页面
  • a 进入 b,缓存 a页面
  • b 进入 c,缓存 a、b 页面
  • 离开 c,移除 b 的缓存
  • 离开 b,移除 a 的缓存

注意

  • 以下代码是从项目中提取出来的,提取后未验证,注意踩坑
  • 仅作为 笔记、参考思路

1、新建工具文件

  • src/utils/keepAliveVerification.js
/**
 *
 *
 * 页面 是否使用 keep-alive 动态验证
 * 关键条件:meta.cachedRouteNames
 * 获取缓存条件,例:a页面访问b页面,在a页面路由的meta.cachedRouteNames中,是否存在 b页面的路由名称,存在则表示缓存(表示路由是从a页面进入的b页面)
 */
import store from "@/store/index";

// 从公共模块中读取 需要缓存的路由名称
const { cachedRouteNames } = store.state.common;

// 路由发生改变
const changeRoutes = (route, type) => {
  // 得到 路由对应的组件名称
  const routeComponentName = route.components.default.name;
  if (
    routeComponentName && type === "add"
      ? !cachedRouteNames.includes(routeComponentName)
      : cachedRouteNames.includes(routeComponentName)
  ) {
    store.commit("common/update_cachedroutenames", {
      action: type,
      route: routeComponentName
    });
  }
};

// 定义添加缓存组件name函数,设置的时组件的name
const addRoutes = route => {
  changeRoutes(route, "add");
};

// 定义删除缓存组件name函数,设置的是组件的name
const deleteRoutes = route => {
  changeRoutes(route, "delete");
};

// 配置路由keepAlive状态
const setRouterBeforeEach = router => {
  // 路由守卫
  router.beforeEach((to, from, next) => {
    // 获取缓存条件,例:a页面访问b页面,在a页面路由的meta.cachedRouteNames中,是否存在 b页面的路由名称
    const fromCachedRouteNames = from.meta.cachedRouteNames;

    // 获取当前路由所在的路由信息
    const fromRoute =
      from && from.matched instanceof Array
        ? from.matched[from.matched.length - 1]
        : null;

    // 读取前往界面的路由结构,前往的界面存在多级嵌套(多层布局方式包裹)
    to.matched.forEach((item, index) => {
      // 当 index 小于 路由嵌套层级,追加 路由层级嵌套组件结构
      if (index < to.matched.length - 1) {
        // 如果使用了 keepAlive
        if (item.meta.keepAlive) {
          addRoutes(item);
        } else {
          deleteRoutes(item);
        }
      } else if (index === to.matched.length - 1) {
        // 如果路由访问的真实地址(路由嵌套层级的最后一层),在当中的条件满足判断后,即:a页面缓存条件是(从a页面进入的b页面,才进行缓存a页面)
        if (
          from.meta.keepAlive &&
          (fromCachedRouteNames && fromCachedRouteNames.includes(item.name))
        ) {
          // 缓存当前页面
          addRoutes(fromRoute);
        } else {
          // 不存在,删除当前路由的 缓存信息
          deleteRoutes(item);
        }
      }
    });

    next();
  });
};

export default {
  setRouterBeforeEach
};

2、配置 store module

  • src/store/modules/common.js
/***
 *
 * 公共文件,用于 存储页面动态缓存(keep-alive)
 *
 */

const UPDATE_CACHEDROUTENAMES = "update_cachedroutenames";
const state = {
  // 页面activated时是否需要重新加载
  activatedReloadData: true,
  // 缓存的路由列表
  cachedRouteNames: []
};

const mutations = {
  [UPDATE_CACHEDROUTENAMES](st, { action, route }) {
    const methods = {
      add: () => {
        st.cachedRouteNames.push(route);
      },
      delete: () => {
        st.cachedRouteNames.splice(
          st.cachedRouteNames.findIndex(e => e === route),
          1
        );
      }
    };
    methods[action]();
  }
};

export default {
  namespaced: true,
  state,
  mutations
};

3、导入配置的 store module

  • src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
......
import common from './modules/common'

Vue.use(Vuex)

const store = new Vuex.Store({
  modules: {
    ......
    common
  },
  getters
})

export default store

4、页面 layout文件中,添加 keep-alive include 配置

  • src/layout/AppMain.vue
<template>
  <section class="app-main">
    <transition name="fade-transform" mode="out-in">
      <keep-alive :include="cachedViews">
        <router-view />
      </keep-alive>
    </transition>
  </section>
</template>

<script>
export default {
  name: "AppMain",
  computed: {
    cachedViews() {
      // 动态缓存配置
      return this.$store.state.common.cachedRouteNames;
    }
  },
};
</script>

5、使用 动态缓存 工具函数

  • src/main.js
......
// 导入路由
import router from './router'

// 导入 keey-alive缓存 动态验证文件
import keepAliveVerification from './utils/keepAliveVerification.js';
// 配置路由keepAlive状态
keepAliveVerification.setRouterBeforeEach(router);

6、路由结构变更

  • src/router/index.js
// 导入布局文件
import Layout from "@/layout/AppMain.vue";

// 页面导出的路由配置
export const constantRoutes = [
    ......
    {
        path: "/user",
        component: Layout,
        redirect: "/userList",
        children: [
          {
            name: "Homr",
            path: "/userList",
            hidden: true,
            component: resolve => require(["@/views/user-list/index.vue"], resolve),
            hidden: true,
            meta: {
              title: "用户列表页面",
              icon: "user-list-icon",
              cachedRouteNames:['userDetail'],// 说明:当进入 userDetail 页面时,缓存当前页面
            },
            children: [
                {
                    name: "userDetail",
                    path: "/userList/detail",
                    hidden: true,
                    component: resolve => require(["@/views/index/detail/index.vue"], resolve),
                    meta: {
                      title: "用户详情界面",
                    },
                }
              ]
            }
          
        ]
      }
  ]

写在最后

如有问题,欢迎指教,共同学习