vue-router 提供了 vue 路由跳转的功能,有时候我们需要缓存上一个页面,避免重新渲染耗费时间,所以要对一些组件做缓存

keep-alive 组件

keep-alive 是 vue 内置的组件,用来缓存包裹的动态组件,当组件切换时候,不会销毁不活动的组件,他有两个属性includeexclude ,可以用来有条件地缓存组件,值可以是逗号分隔的字符串,正则表达式或者一个数组

<!-- 逗号分隔字符串 -->
<keep-alive include="a,b">   <component :is="view"></component> </keep-alive>
<!-- 正则表达式 (使用 `v-bind`) -->
<keep-alive :include="/a|b/">   <component :is="view"></component> </keep-alive>
<!-- 数组 (使用 `v-bind`) -->
<keep-alive :include="['a', 'b']">
  <component :is="view"></component>
</keep-alive>

匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值)。匿名组件不能被匹配。

不会在函数式组件中正常工作,因为它们没有缓存实例。

include 实现缓存

本文主要用 include 来实现前进时候组件缓存,后退时候组件销毁的功能

假如我们有一个需求,列表 -> 详情,详情 -> 列表,由于列表可能有查询,分页的功能,不需要销毁而是直接进入详情页面,这样返回就不需要重新生成新的组件导致原有的查询或者分页失效

那么只要在 keep-alive 添加 include 组件名数组,如下,PostList 文章列表组件会缓存,而文章详情就不会被缓存

<keep-alive :include="r">
  <router-view></router-view>
</keep-alive>

在 data 里面声明需要缓存的组件名

data() {
  return {
    r: ['PostList'],
  };
},

这样子就解决了两个页面之间的前进加载新页面,后退加载缓存页面的功能

多页面跳转和缓存

如果是多个页面的情况,相对比较复杂点,比如 a->b->c->d,首先记录一下路由的来源,比如 a->b->c,我们需要缓存的是 a 和 b,可以通过路由定义的 meta 属性来记录

{
  path: '/b',
  meta: {
      from: 'a'    // from组件名
  },
  name: 'bComponent',
  component: bComponent
},
{
  path: '/c',
  meta: {
      from: 'b'    // from组件名
  },
  name: 'cComponent',
  component: cComponent
}

在初始化 r 属性的时候,默认 a 路由是必须缓存的,初始值为 r = ['a'],通过监听 $route 属性来动态设置 keepAliveinclude 属性值

app = {
watch: {
$route(newRoute, oldRoute) {
let newRouteName = newRoute.name, // 新的路由名称
newRouteFrom = newRoute.meta.from; // 新的路由来源
let oldRouteName = oldRoute.name; // 旧的路由名称
if (newRouteName && newRouteFrom && oldRouteName) {
if (newRouteFrom.toLowerCase() === oldRouteName.toLowerCase()) {
// 新的路由来源和旧的路由名称相同,新的组件就缓存
this.r.push(newRouteName);
} else {
// 否则弹出
let removeCmp = this.r.pop();
}
} else {
// 防止home组件缓存被弹出
if (this.r.length > 1) {
let removeCmp = this.r.pop();
}
}
},
},
};

如果在 /b 路由的时候手动刷新页面,那么需要从 b 开始缓存,一般在最后一个路由的时候是不需要缓存的,所以在 created 或者 mounted 钩子函数里面判断

const app = {
created() {
// 刷新进入中间路由的情况
if (this.$route.name !== 'a' && this.$route.name !== 'd') {
this.r.push(this.$route.name);
}
},
};