Vue中keep-alive介绍和使用

1,813 阅读3分钟

「这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战

前提

当我们正在商品列表浏览商品,浏览了很长一段的商品,然后点击切换到其他页面了,再次点击回到商品列表页面,还在之前浏览的地方,类似这种功能是怎么实现的呢?

我们想到了vue官网提供的keep-alive的方法(一种内部封装好的组件)。

官网介绍: keep-alive只能包裹在封装的组件中,而不能直接包裹在类似divh1等原生标签上,那么我们要想保持状态,就得把那部分封装在一个功能性的组件上。

keep-alivevue2.0加入的一个特性, 能缓存某个组件,或者某个路由。它的好处:

  1. 节省性能消耗,避免一个组件频繁重新渲染,节省开支
  2. 保存用户状态,比如说:我们在填写收货地址的页面,需要跳转到另一个页面通过定位选择地址信息再返回继续填写,这时候需要缓存收货地址页面,避免跳转页面导致用户数据丢失。

实现方法

1. hack手法

  • 利用meta.keeAlive字段来进行判断,
// 首页
{
  path: '/',
  name: 'Home',
  component: Home,
  meta: {
    keepAlive: true
  }
},
// 列表
{
  path: '/list',
  name: 'List',
  component: List,
  meta: {
    keepAlive: true
  }
},
// 详情
{
  path: '/detail',
  name: 'Detail',
  component: Detail,
  meta: {
    keepAlive: true
  }
}
  • 进入到[app.vue]页面中我们为<router-view>添加一个key,这个key就像是我们使用v-for循环所定义的一样,将key的作为一个标识,作用于vue在虚拟 dom 进行diff算法,提高渲染效率。
<template>
  <div id="app">
    <keep-alive>
      <router-view v-if="$route.meta.keepAlive" :key="key" />
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive" :key="key" />
  </div>
</template>

<script>
  export default {
    computed: {
      key() {
        return this.$route.fullPath;
      }
    }
  };
</script>
  • 然后我们对其需要强制刷新的页面参数里加个时间戳,这样就可以实现按需keep-alive了。
onClick() {
      this.$router.push({
        path: '/product',
        query: {
          t: +new Date()
        }
      })
  }

meta 路由元信息

使用 vue-router 提供的 meta 对象,给需要缓存如首页、列表页、商详等添加一个字段,用来判断用户是前进还是后退以及是否需要 keep-alive

  1. 首先我们需要在router.jsmeta对象里定义两个值:

    • keepAlive:这个路由是否需要缓存

    • deepth:深度,也就是页面之间的前进后退的层次关系

    // 首页
    {
      path: '/',
      name: 'Home',
      component: Home,
      meta: {
        keepAlive: true,
        deepth: 1
      }
    },
    // 列表
    {
      path: '/list',
      name: 'List',
      component: List,
      meta: {
        keepAlive: true,
        deepth: 2
      }
    },
    // 详情
    {
      path: '/detail',
      name: 'Detail',
      component: Detail,
      meta: {
        keepAlive: true,
        deepth: 3
      }
    }
    
  2. 然后我们在app.vue中根据 meta 对象定义一下:

<div id="app">
    <keep-alive :include="include">
      <router-view v-if="$route.meta.keepAlive" />
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive" />
</div>
  1. 最后我们需要实时的监听路由
data() {
    return {
      include: []
    };
  },
  watch: {
    $route(to, from) {
      // 如果要to(进入)的页面是需要keepAlive缓存的,把name push进include数组中
      if (to.meta.keepAlive) {
        !this.include.includes(to.name) && this.include.push(to.name);
      }
      // 如果 要 form(离开) 的页面是 keepAlive缓存的,
      // 再根据 deepth 来判断是前进还是后退
      // 如果是后退:
      if (from.meta.keepAlive && to.meta.deepth < from.meta.deepth) {
        const index = this.include.indexOf(from.name);
        index !== -1 && this.include.splice(index, 1);
      }
    }
  },

主要步骤其实两步:设置meta监听路由并判断

这里有一定要注意的是:你的路由中定义的 name 和页面中定义的 name 一定要全等,并区分大小写!!!

对比

  • 两者相比,第1种更加的实用,比一种简单,但是样式有点不太美观,因为路由中会带时间戳字符串;

  • 第2种算是比较完美,设置起来也不难,只是对团队人员的规范性要求比较高。