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 选项的键值)。匿名组件不能被匹配。

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

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 属性值

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 钩子函数里面判断

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