当前位置: 首页 > article >正文

Vue 的 keep-alive

什么是 keep-alive

<keep-alive> 是一个内置组件,用于缓存组件实例,从而提高应用的性能。当包裹动态组件时,<keep-alive> 会缓存不活跃的组件实例,而不是销毁它们。这使得当组件重新激活时,可以保留其状态,避免重新渲染,从而提升用户体验和性能。

主要用途

  1. 缓存组件状态:当组件在不同路由之间切换时,<keep-alive> 可以缓存组件的状态,避免每次切换时重新渲染。
  2. 优化性能:通过缓存组件实例,减少不必要的 DOM 操作和计算,提高应用的响应速度。

 基本用法:

<template>
  <div>
    <button @click="activeComponent = 'ComponentA'">Component A</button>
    <button @click="activeComponent = 'ComponentB'">Component B</button>

    <keep-alive>
      <component :is="activeComponent"></component>
    </keep-alive>
  </div>
</template>

<script>
import ComponentA from './ComponentA.vue';
import ComponentB from './ComponentB.vue';

export default {
  components: {
    ComponentA,
    ComponentB
  },
  data() {
    return {
      activeComponent: 'ComponentA'
    };
  }
};
</script>

在这个例子中,<keep-alive> 包裹了 <component>,当 activeComponent 切换时,组件实例会被缓存而不是销毁。

  1. **include 和 exclude**:用于控制哪些组件需要缓存,支持字符串、正则表达式或数组。
<keep-alive include="ComponentA, ComponentB" exclude="ComponentC">
  <router-view></router-view>
</keep-alive>

2. **max**:用于指定缓存的组件数量,当超出这个数量时,最久未使用的组件实例将被销毁。

<keep-alive :max="10">
  <router-view></router-view>
</keep-alive>
与 <router-view> 一起使用:
<template>
  <div>
    <router-link to="/a">Component A</router-link>
    <router-link to="/b">Component B</router-link>

    <keep-alive :include="['ComponentA']" :max="10">
      <router-view></router-view>
    </keep-alive>
  </div>
</template>

keep-alive 的源码分析

export default {
  name: 'KeepAlive',
  abstract: true, // 这是一个抽象组件,表示它不会直接渲染到 DOM 上

  props: {
    include: patternTypes, // 要缓存的组件
    exclude: patternTypes, // 不缓存的组件
    max: [String, Number] // 最大缓存数
  },

  created () {
    this.cache = Object.create(null); // 缓存对象
    this.keys = []; // 用来记录缓存的顺序
  },

  destroyed () {
    for (const key in this.cache) {
      pruneCacheEntry(this.cache, key, this.keys);
    }
  },

  watch: {
    include (val) {
      pruneCache(this, name => matches(val, name));
    },
    exclude (val) {
      pruneCache(this, name => !matches(val, name));
    }
  },

  render () {
    const slot = this.$slots.default;
    const vnode = getFirstComponentChild(slot); // 获取第一个子组件

    if (vnode) {
      const componentOptions = vnode.componentOptions;
      const name = getComponentName(componentOptions);
      
      if (name && (
        (this.include && !matches(this.include, name)) ||
        (this.exclude && matches(this.exclude, name))
      )) {
        return vnode; // 如果不匹配 include/exclude,直接返回,不缓存
      }

      const key = vnode.key == null
        ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
        : vnode.key;

      if (this.cache[key]) {
        vnode.componentInstance = this.cache[key].componentInstance; // 从缓存中取出实例
        remove(this.keys, key); // 移除旧的位置
        this.keys.push(key); // 重新放到最后,更新 LRU 位置
      } else {
        this.cache[key] = vnode; // 缓存新实例
        this.keys.push(key);

        // 如果超过最大缓存数,移除最早的实例
        if (this.max && this.keys.length > parseInt(this.max)) {
          pruneCacheEntry(this.cache, this.keys[0], this.keys, this._vnode);
        }
      }

      vnode.data.keepAlive = true; // 标记组件为 keep-alive
    }

    return vnode || (slot && slot[0]); // 返回 vnode
  }
};


http://www.kler.cn/a/388072.html

相关文章:

  • Android中桌面小部件的开发流程及常见问题和解决方案
  • AWS认证SAA-C0303每日一题
  • 网站小程序app怎么查有没有备案?
  • 基于Python+Django+Vue3+MySQL实现的前后端分类的商场车辆管理系统
  • 除了 Postman,还有什么好用的 API 调试工具吗
  • 知识库管理系统:企业数字化转型的加速器
  • CSRF 跨站请求伪造的实现原理和预防措施
  • Windows 使用批处理脚本快速释放被占用的端口
  • 深度学习:预训练(Pre-training详解
  • 【如何在 Linux 和 Android 系统中杀死进程】
  • 【模型学习之路】手写+分析GAT
  • 前端 Flex 布局语法详解
  • Python接口自动化测试自学指南(项目实战)
  • 海外云手机在出海业务中的优势有哪些?
  • Elasticsearch实战使用
  • u盘怎么重装电脑系统_u盘重装电脑系统步骤和详细教程【新手宝典】
  • Hive中查看字段中是否包含某些字符串的函数
  • Git 入门篇(三)
  • 发布 VectorTraits v3.0(支持 X86架构的Avx512系列指令集,支持 Wasm架构及PackedSimd指令集等)
  • 从0开始深度学习(24)——填充和步幅
  • 通过 SSH 连接远程 Ubuntu 服务器
  • 24下半年教资面试资源(幼儿+小学+初中+高中+各科)逐字稿
  • Redis集群——针对实习面试
  • JDK8主要特性
  • React 中 `key` 属性的警告及其解决方案
  • C++设计模式精选面试题及参考答案