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

相关推荐
zhedream几秒前
Vue 3 Teleport 报错实录:从 patch 时机到 `defer` 属性
前端·vue.js
雁北向1 分钟前
自定义指令 数值输入显示优化 巴飞特 测试
前端·vue.js
研☆香3 分钟前
jQuery补充知识点
前端·javascript·jquery
lichenyang4536 分钟前
打车票根卡片 UI 重构:从 Circle 挖洞到 clipShape PathShape,再到 100% 自适应
前端
傅科摆 _ py9 分钟前
AI Ping 平台使用教程
java·前端·人工智能
lichenyang45314 分钟前
聊天历史从 Preferences 搬到关系型数据库(RDB):为什么换、怎么换、踩了什么坑
前端
HjhIron20 分钟前
从栈到队列,再到链表:前端开发者必知的线性数据结构
前端·javascript
PedroQue9920 分钟前
uni-app路由管理神器:vue-router风格体验
前端·uni-app
用户17335980753720 分钟前
花两周用 Vue 3 做了个 PDF 工具站,我在生产环境踩了 8 个坑
前端·vue.js
风骏时光牛马21 分钟前
TypeScript 泛型与工具类型实战:企业级通用数据请求封装完整案例
前端