前引

keep-alive是vue自带的一个内置组件,可以实现缓存包裹在其中的动态切换组件。

我这里是和路由结合全局使用

全局添加keep-alive

在界面切换的router-view处做修改

1
2
3
4
5
  <router-view v-slot="{ Component }">
    <keep-alive :include="cachedRoutes">
      <component :is="Component" :key="$route.fullPath" />
    </keep-alive>
  </router-view>

cachedRoutes:为需要缓存界面路由name,可以根据使用情况设置,我这里写到了pinia中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
export const settingStore = defineStore("setting", {
  state: () => {
    return {
      cachedRoutes: Array<string>(), // 缓存的路由名称列表
    };
  },
  getters: {
      getCachedRoutes(): string[] {
      return this.cachedRoutes;
    },
  },
  actions: {
    addRouteToCache(routeName: string) {
      if (!this.cachedRoutes.includes(routeName)) {
        this.cachedRoutes.push(routeName);
      }
    },
    removeRouteFromCache(routeName: string) {
      const index = this.cachedRoutes.indexOf(routeName);
      if (index !== -1) {
        this.cachedRoutes.splice(index, 1);
      }
    },
  },
});

设置路由

路由定义在需要缓存的界面路由mate中添加keepAlive: true

1
2
3
4
5
6
7
8
9
    {
      path: "/test/pageA",
      name: "pageA",
      meta: { title: "界面A", keepAlive: true },
      component: () =>
        import(
          "@/views/test/pageA/index.vue" as string
        ),
    }

设置路由守卫,通过路由守卫向cachedRoutes 中添加需要缓存页面name

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const setRouteCache = (event: any) => {
  if (event.state) {
    const { name, meta } = currentRoute as any;
    if (meta.keepAlive) settingStore().removeRouteFromCache(name);
  }
};
// 监听浏览器后退事件
window.addEventListener("popstate", setRouteCache);

router.beforeEach(async (to: any, _from: any, next) => {
  // 设置浏览器标题
  document.title = to.meta.title;

  window.history.state.action = to.name;
  currentRoute = _from;
  if (to.matched) {
    to.matched.forEach((record: any) => {
      if (record.name && record.components?.default) {
        const component = record.components.default;
        if (typeof component === "function") {
          // 处理异步组件
          component().then((resolved: any) => {
            if (!resolved.default.name) {
              resolved.default.name = record.name;
            }
          });
        } else if (!component.name) {
          // 处理普通组件
          component.name = record.name;
        }
      }
    });
  }
  if (to.meta.keepAlive) {
    const settingSate = settingStore();
    settingSate.addRouteToCache(to.name);
  }
  next();
});

其中下面这部分代码是设置页面name和路由的name绑定如果一致的可以去除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  if (to.matched) {
    to.matched.forEach((record: any) => {
      if (record.name && record.components?.default) {
        const component = record.components.default;
        if (typeof component === "function") {
          // 处理异步组件
          component().then((resolved: any) => {
            if (!resolved.default.name) {
              resolved.default.name = record.name;
            }
          });
        } else if (!component.name) {
          // 处理普通组件
          component.name = record.name;
        }
      }
    });
  }