keep-alive 使用(Vue.js)

本文启发自于在项目“中国石油 - 云梦泽智慧平台 - 改版”项目缺陷记录
内容来源自《vue 中 keep-alive 的理解和使用》、《vue 的 keep-alive 详解

keep-alive 是什么?

keep-alive 是一个内置组件,它的功能是在多个组件间动态切换时缓存被移除的组件实例,而不是销毁它们,可防止重复渲染 DOM

实现原理:

keep-alive 实现原理是:

渲染一个组件时,根据组件通过以下代码组件中的第一个有效节点的 name

const vnode = getFirstComponentChild(this.$slots.default)

// 文心对 getFirstComponentChild 函数解释如下
在 Vue.js 的源码实现中,存在一个名为 getFirstComponentChild 的函数,其作用是遍历一个组件的子节点(vnode),并返回第一个具有 componentOptions 属性的子组件节点
该函数是 Vue.js 内部用于虚拟 DOM 处理的辅助函数,‌并非 Vue.js 提供给开发者在模板或组件中直接调用的公共 API ,开发者通常无需直接使用它

判断是否为需要缓存组件

  • 如果没有缓存,将需要缓存的组件保存在一个 cache 对象中,包含 nametagcomponentInstance(组件实例),然后正常返回该组件
  • 如果在 cache 对象中已经存在此组件,则将缓存的组件实例直接赋值给当前组件;

匹配规则:

  • 首先匹配组件的 name 选项
  • 如果 name 选项不可用,则匹配它的局部注册名称(父组件 components 选项的键值)
  • 匿名组件,不可匹配(路由组件没有 name 选项,并且没有注册的组件名)
  • 只能匹配当前被包裹的组件,不能匹配更下面嵌套的子组件(只能匹配路由组件的 name 选项,不能匹配路由组件里面的嵌套组件 name 选项)
  • 不会在函数式组件中正常工作,因为他们没有缓存实例
  • exclude 的优先级 > include

使用:

keep-alive 支持接收三个参数(都可选):

属性名属性值描述
include字符串或正则表达式只有 name 匹配的组件 会被缓存
exclude字符串或正则表达式任何 name 匹配的组件都 不会被缓存
max数字最多可以缓存多少组件实例。
类似一个 LRU 缓存:如果缓存的实例数量即将超过指定的那个最大数量,则最久没有被访问的缓存实例将被销毁,以便为新的实例腾出空间

普通组件中使用 keep-alive

<!-- keep-alive 里面所有的组件都会缓存 -->
<keep-alive>
    <component :is="componentName"/>
</keep-alive>

<!-- 只缓存组件名称为 a 或 b 的组件 -->
<keep-alive :include="['a','b']">
<!-- <keep-alive :include="['a','b']"> --> // 第二种写法
<!-- <keep-alive :include="/a|b/"> --> // 第三种正则写法
    <components :is="componentName" />
</keep-alive>

<!-- 动态判断 -->
<keep-alive :include="includedComponents">
    <router-view></router-view>
</keep-alive>

<!-- 不缓存组件名称为 b 的组件 -->
<keep-alive exclude="b">
    <components :is="componentName" />
</keep-alive>

<script>
export default {
  data () {
    return {
        includedComponents: "test-keep-alive",
        currentComponent: 'test-keep-alive'
    }
  },
 watch: {
    // 监听 currentComponent 的变化,动态决定是否需要缓存
    currentComponent(newComponent, oldComponent) {
      if (/* 某些条件 */) {
        this.includedComponents.push(newComponent);
      } else {
        this.includedComponents = [];
      }
    }
  }
}
</script>

适用场景:

在项目中我们将 keep-aliverouter-view 结合使用,实现切换路由后仍然保留之前的路由页面的状态

// 所有匹配到的路由组件都会被缓存
<keep-alive>
    <router-view />
</keep-alive>

通过在路由配置的 meta 对象中添加 keepAlive 属性控制对应的路由是否需要被缓存

router-view 路由配置

{
    path: '路由访问路径',
    component: () => import(‘路由引用文件路径’),
    name: '路由名称',
    meta: {
        keepAlive: true // 此路有会被缓存
    }
}

在页面引用过程中通过在路由配置的 meta 对象中添加 keepAlive 属性控制对应的路由是否需要被缓存

<keep-alive>
    <router-view
        v-if="$route.meta.keepAlive"
    />
</keep-alive>

也可以在子页面通过拦截守卫 beforeRouteLeave 动态设置 route.metakeepAlive 属性来实现其他需求

例如:首页是A页面。B 页面跳转到 A,A 页面需要缓存。C 页面跳转到 A,A 页面不需要被缓存

<script>
// B 页面
export default {
    data() {
        return {};
    },
    methods: {},
    beforeRouteLeave(to, from, next) {
        // 设置下一个路由的 meta
        // B 跳转到 A 时,让 A 缓存,即不刷新
        to.meta.keepAlive = true;  
        next();
    }
};
</script>

源码解析:

请移步至《vue 的 keep-alive 详解》,文中有详细的源码解析

分类: 工作相关

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注