Vue实现按需动态keep-alive

一、场景描述

项目中常见的一个场景是:

主页->列表页->详情页层层深入,详情页->列表页->主页层层返回。

为了提升用户体验和性能,我们希望可以动态缓存列表页面:

从详情页->列表页时,用缓存中的列表页,不用重新请求数据。

从列表页->主页时,注销掉列表页,再进入列表页时,获取最新的数据。

现在,我们用keep-alive来实现这个功能。

二、keep-alive知识回顾

官方文档这样介绍keep-alive

keep-alive

  • Props

    • include - 字符串或正则表达式。只有名称匹配的组件会被缓存。

    • exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。

    • max - 数字。最多可以缓存多少组件实例。

  • 用法:

    <keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition> 相似,<keep-alive> 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。

    当组件在 <keep-alive> 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。

三、功能实现

01

定义router

用keepAlive表示路由对应的组件是否需要缓存、deepth表示当前路由的层级。

代码:

export default new Router({
  routes: [
    {
      path: '/',
      name: 'index',
      meta: {
        deepth: 0
      },
      component: Index
    },
    {
      path: '/list',
      name: 'list',
      meta: {
        deepth: 1, // 当前路由层级
        keepAlive: true // 是否需要缓存
      },
      component: List
    },
    {
      path: '/detail',
      name: 'detail',
      meta: {
        deepth: 2
      },
      component: Detail
    }
  ]
})

02

按需缓存router-view

keep-alive组件的include属性表示只有name匹配的组件会被缓存。我们可以动态修改include属性的值来实现按需缓存。

<keep-alive :include="includeArr.length==0?' ':includeArr.join(',')">
  <router-view ></router-view>
</keep-alive>

如果要to(进入)的页面是需要keepAlive缓存的,把to.name push进includeArr数组。

如果要form(离开)的页面是keepAlive缓存的,再根据deepth来判断是前进还是后退。如果是后退,删除掉includeArr数组里from.name,也就是注销掉缓存组件。

$route (to, from) {
  // 如果 要 to(进入) 的页面是需要 keepAlive 缓存的,把 name push 进 includeArr数组
  if (to.meta.keepAlive) {
    !this.includeArr.includes(to.name) && this.includeArr.push(to.name)
  }
  // 如果 要 form(离开) 的页面是 keepAlive缓存的,再根据 deepth 来判断是前进还是后退,如果是后退,需要注销缓存的组件。
  if (from.meta.keepAlive && to.meta.deepth < from.meta.deepth) {
    var index = this.includeArr.indexOf(from.name)
    index !== -1 && this.includeArr.splice(index, 1)
  }
}

注意:keep-alive组件的include属性匹配的是组件的name值,includeArr数组存的是router的name值,所以,我们要把router的name属性设置成router对应组件的name一样的。

d91a20f807ebd371ee6cf7f901a58122.png

完整代码:

<template>
  <div id="app">
      <router-link :to="{name: 'index'}">index</router-link>
      <router-link :to="{name: 'list'}">list</router-link>
      <router-link :to="{name: 'detail'}">detail</router-link>
      <keep-alive :include="includeArr.length==0?' ':includeArr.join(',')">
        <router-view ></router-view>
      </keep-alive>
  </div>
</template>

<script>
export default {
  name: 'App',
  data: () => {
    return {
      includeArr: []
    }
  },
  watch: {
    $route (to, from) {
      // 如果 要 to(进入) 的页面是需要 keepAlive 缓存的,把 name push 进 include数组
      if (to.meta.keepAlive) {
        !this.includeArr.includes(to.name) && this.includeArr.push(to.name)
      }
      // 如果 要 form(离开) 的页面是 keepAlive缓存的,再根据 deepth 来判断是前进还是后退,如果是后退,需要清掉缓存的组件。
      if (from.meta.keepAlive && to.meta.deepth < from.meta.deepth) {
        var index = this.includeArr.indexOf(from.name)
        index !== -1 && this.includeArr.splice(index, 1)
      }
    }
  }
}
</script>

<style>

</style>

这样就实现了按需动态keep-alive。

四、效果

打开vue-devtool里注意观察list组件的变化(灰色为缓存状态的组件)。

1.从首页进入列表页:list组件被缓存,执行以下生命周期函数;

beforeCreate

created

beforeMount

mounted

activated

2.从列表页进入详情页:list组件并没有被注销,执行以下生命周期函数;

deactivated

3.从详情页再返回列表页:没有重新渲染list组件,用的是缓存中的list组件,执行以下生命周期函数;

activated

4.从列表页返回首页:缓存的list组件被注销,执行以下生命周期函数;

deactivated

beforeDestroy

destroyed

5.再次从首页进入列表页:重新渲染list组件,list组件执行以下生命周期函数;

beforeCreate

created

beforeMount

mounted

activated

d2c7ba76a18b34ee7dc49dc1d9e01583.gif

如果您有关于本文的任何问题,欢迎沟通!感谢阅读~

2f3fe458eecc37a3d2db02878d681b05.png

104d4903515895d5d513ffeb15577092.jpeg

扫描二维码

关注更多精彩

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值