Vue 中 keep-alive 组件的生命周期钩子

Vue 中 keep-alive 组件的生命周期钩子

本文来自于我关于 Vue生命周期钩子 的系列文章。欢迎阅读、点评与交流~
1、Vue 中的生命周期钩子
2、Vue 中 keep-alive 组件的生命周期钩子

1. keep-alive 组件概述

keep-alive 是 Vue 的内置组件,用于缓存不活动的组件实例,而不是销毁它们。这样可以:

  • 保留组件状态,避免重新渲染
  • 提高应用性能
  • 减少重复的 DOM 操作

2. 基本用法

vue 复制代码
<template>
  <div>
    <keep-alive>
      <component :is="currentComponent"></component>
    </keep-alive>
  </div>
</template>

3. 专门的生命周期钩子

keep-alive 包裹的组件会获得两个额外的生命周期钩子:

activated

  • 调用时机:组件被激活(从缓存中取出并插入到 DOM 中)时调用
  • 使用场景:重新获取数据、开启定时器、重新绑定事件等

deactivated

  • 调用时机:组件被停用(从 DOM 中移除并存入缓存)时调用
  • 使用场景:清除定时器、取消事件监听、释放资源等

4. 完整生命周期执行顺序

首次加载

javascript 复制代码
// 组件第一次进入时
created() → mounted() → activated()

切换到其他组件(当前组件被缓存)

javascript 复制代码
// 当前组件被离开
deactivated()

再次切换回来

javascript 复制代码
// 再次进入缓存的组件
activated()

组件被销毁(当离开路由或 keep-alive 被移除)

javascript 复制代码
// 如果是直接离开路由
deactivated() → beforeDestroy() → destroyed()

// 注意:如果组件被 keep-alive 缓存,则不会触发 beforeDestroy 和 destroyed

5. 实际示例

vue 复制代码
<template>
  <div>
    <button @click="toggle">切换组件</button>
    <keep-alive>
      <ComponentA v-if="showA" />
      <ComponentB v-else />
    </keep-alive>
  </div>
</template>

<script>
// ComponentA.vue
export default {
  name: 'ComponentA',
  data() {
    return {
      timer: null,
      count: 0
    }
  },
  
  created() {
    console.log('ComponentA created')
  },
  
  mounted() {
    console.log('ComponentA mounted')
  },
  
  activated() {
    console.log('ComponentA activated')
    // 重新开启定时器
    this.timer = setInterval(() => {
      this.count++
      console.log('定时器运行中:', this.count)
    }, 1000)
  },
  
  deactivated() {
    console.log('ComponentA deactivated')
    // 清除定时器
    if (this.timer) {
      clearInterval(this.timer)
      this.timer = null
    }
  },
  
  beforeDestroy() {
    console.log('ComponentA beforeDestroy')
  },
  
  destroyed() {
    console.log('ComponentA destroyed')
  }
}
</script>

6. keep-alive 的属性配置

vue 复制代码
<!-- 只缓存特定组件 -->
<keep-alive include="ComponentA,ComponentB">
  <component :is="currentComponent"></component>
</keep-alive>

<!-- 排除某些组件 -->
<keep-alive exclude="ComponentC">
  <component :is="currentComponent"></component>
</keep-alive>

<!-- 使用正则表达式 -->
<keep-alive :include="/ComponentA|ComponentB/">
  <component :is="currentComponent"></component>
</keep-alive>

<!-- 限制最大缓存实例数 -->
<keep-alive :max="5">
  <component :is="currentComponent"></component>
</keep-alive>

7. 与 Vue Router 结合使用

javascript 复制代码
// router.js
const routes = [
  {
    path: '/page1',
    component: Page1,
    meta: {
      keepAlive: true  // 需要缓存
    }
  },
  {
    path: '/page2',
    component: Page2,
    meta: {
      keepAlive: false // 不需要缓存
    }
  }
]
vue 复制代码
<!-- App.vue -->
<template>
  <div id="app">
    <keep-alive>
      <router-view v-if="$route.meta.keepAlive"></router-view>
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive"></router-view>
  </div>
</template>

8. 注意事项和最佳实践

注意事项:

  1. name 属性必需 :组件必须有 name 选项才能被 include/exclude 匹配
  2. 嵌套 keep-alive:Vue 2.2.0+ 支持嵌套使用,但应避免过度使用
  3. 动态组件 :与 <component :is="..."> 结合时最有用
  4. 内存管理 :注意内存泄漏,及时在 deactivated 中清理资源

最佳实践:

javascript 复制代码
export default {
  name: 'MyComponent', // 必须设置 name
  data() {
    return {
      // 数据会被缓存
    }
  },
  activated() {
    // 可以在这里重新获取可能需要更新的数据
    if (this.needsRefresh) {
      this.fetchData()
    }
  },
  deactivated() {
    // 清理工作
    this.cancelPendingRequests()
    clearInterval(this.timer)
  },
  methods: {
    // 如果需要刷新数据的逻辑
    fetchData() {
      // 获取数据
    },
    cancelPendingRequests() {
      // 取消未完成的请求
    }
  }
}

9. Vue 3 中的变化

在 Vue 3 中,keep-alive 的用法基本保持不变,但生命周期钩子名称有变化:

javascript 复制代码
// Vue 3 Composition API
import { onActivated, onDeactivated } from 'vue'

export default {
  setup() {
    onActivated(() => {
      console.log('组件被激活')
    })
    
    onDeactivated(() => {
      console.log('组件被停用')
    })
  }
}

总结

keep-alive 组件的生命周期钩子 activateddeactivated 为缓存组件提供了精确的控制能力。合理使用这些钩子可以有效管理组件状态、优化性能,同时避免内存泄漏等问题。在实际开发中,结合路由配置和动态组件,可以创建出体验更流畅的单页应用。

相关推荐
北风toto4 分钟前
为什么 IntelliJ IDEA Community 无法开发 Vue?——附解决方案
java·vue.js·intellij-idea
@PHARAOH8 分钟前
HOW - 构建一个轻量前后端一体服务
前端·微服务·服务端
无限进步_19 分钟前
【C++】C++11的类功能增强与STL变化
java·前端·数据结构·c++·后端·算法
一只小小Java20 分钟前
Echarts单表多图实现
前端·javascript·echarts
跟着珅聪学java21 分钟前
Element UI 的 Tabs 标签页开发教程
javascript·vue.js·elementui
dunky29 分钟前
Spring AI 深度解析:把 LLM 抽象成 Spring Bean 的底层逻辑
前端
星栈31 分钟前
Rust WASM 文件上传全链路:从浏览器到 S3,一个字节都不能少
前端·前端框架·开源
濮水大叔31 分钟前
告别 Django Admin!这个 NodeJS 全栈框架让你在 DTO 中直接配置 Table/Form 渲染
前端·typescript·node.js
JarvanMo31 分钟前
Flutter 3.44 & Dart 3.12重磅发布!这些新特性太香了
前端
竹林81832 分钟前
用Viem替换ethers.js:一次合约交互的"减负"实战,我总算把TypeScript类型搞明白了
前端·javascript