深度解析vue的生命周期

概述

Vue 生命周期是 Vue 实例从创建到销毁的整个过程,包含多个关键阶段,每个阶段都有对应的生命周期钩子函数,允许我们在特定时机执行自定义逻辑。

每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM。在此过程中,它也会运行被称为生命周期钩子的函数,让开发者有机会在特定阶段运行自己的代码。

生命周期图示

创建

  • 初始化组件的选项(data、methods、computed 等)
  • 建立响应式数据系统
beforeCreate
  1. 时机:实例初始化之后,数据观测和事件配置之前
    DOM正在构建/已完成,CSSOM可能尚未完成
  2. 特点:无法访问到 datacomputedmethods
    可以访问this但值为空对象
  3. 常用场景:
created
  1. 时机:模板编译/挂载之前,初始化选项API之后
  2. 特点:可以访问 datacomputedmethods
    模板还未编译,$el 属性还不存在
  3. 常用场景:异步请求、数据初始化
js 复制代码
created() {
 console.log('created', this.message); // 'Hello Vue'
 console.log('created', this.$el); // undefined
 // 适合在这里调用API获取初始数据
 this.fetchData();
}

挂载

Vue的挂载阶段是组件从创建到渲染到真实DOM的过程,主要包括两个关键钩子函数

beforeMount

  1. 时机:在挂载开始之前被调用,此时模板编译已完成,但尚未将真实DOM插入页面。

  2. 特点:

  • 虚拟DOM已经生成
  • 模板已编译成render函数
  • 尚未替换el内部的HTML内容
  • 无法直接操作DOM元素
  1. 常用场景:
javascript 复制代码
beforeMount() {
  // 1. 最后一次数据修改机会(不会触发重渲染)
  this.someData = this.processData(this.someData);
  
  // 2. 初始化一些不依赖DOM的配置
  this.initConfig();
  
  // 3. 服务端渲染(SSR)中唯一可用的挂载阶段钩子
}

mounted

  1. 时机:实例挂载完成后调用,此时真实DOM已经渲染完成。

  2. 特点:

  • 真实DOM已生成并插入页面
  • 可访问和操作DOM元素
  • 可访问子组件
  • 不保证所有子组件都已挂载(需使用$nextTick)
  1. 常用场景:
javascript 复制代码
mounted() {
  // 1. DOM操作
  this.$refs.input.focus();
  
  // 2. 第三方DOM库初始化
  new Chart(this.$refs.canvas, this.chartData);
  
  // 3. 发起数据请求
  this.fetchData();
  
  // 4. 添加事件监听
  window.addEventListener('resize', this.handleResize);
  
  // 5. 确保子组件已挂载
  this.$nextTick(() => {
    // 所有子组件都已挂载
  });
}

总结对比

特性 beforeMount mounted
访问el ❌ undefined ✅ 可访问
访问真实DOM ❌ 不可 ✅ 可
服务端渲染 ✅ 可用 ❌ 不可用
数据修改 不触发更新 触发更新
主要用途 最后的数据处理 DOM操作、请求、插件初始化

更新

更新阶段是当响应式数据发生变化时,Vue重新渲染组件的过程,主要包括两个关键钩子函数

beforeUpdate

  1. 时机:数据变化后,DOM重新渲染之前调用。

  2. 特点:

    • 可以访问更新前的DOM状态
    • 数据已经更新,但视图尚未同步
    • 适合在更新前访问现有DOM
    • 避免在此阶段修改数据(可能导致无限循环)
  3. 常用场景:

javascript 复制代码
beforeUpdate() {
  // 1. 获取更新前的DOM状态(如滚动位置)
  this.scrollPosition = this.$refs.container.scrollTop;
  
  // 2. 手动移除动态添加的内容
  this.cleanupDynamicContent();
  
  // 3. 记录变化前的状态用于对比
  this.beforeData = { ...this.formData };
  
  // 4. 手动处理DOM操作前的准备工作
  this.$refs.message.innerHTML = '数据更新中...';
  
  // 5. 计算需要保持的状态(如滚动位置保持)
  this.shouldRestoreScroll = true;
}

updated

  1. 时机:数据变化导致DOM重新渲染完成后调用。

  2. 特点:

    • DOM已更新,可以获取最新DOM状态
    • 可以执行依赖于DOM的操作
    • 避免在此修改数据(可能导致无限循环)
    • 不保证所有子组件都已更新(需用$nextTick)
  3. 常用场景:

javascript 复制代码
updated() {
  // 1. 获取更新后的DOM信息(如元素高度、宽度)
  const newHeight = this.$refs.content.offsetHeight;
  
  // 2. 更新完成后滚动到底部或指定位置
  if (this.autoScroll) {
    this.$refs.chatContainer.scrollTop = 
      this.$refs.chatContainer.scrollHeight;
  }
  
  // 3. 使用$nextTick确保所有子组件更新完成
  this.$nextTick(() => {
    this.updateComplete = true;
  });
  
  // 4. 第三方图表库重新渲染
  if (this.chart) {
    this.chart.resize();
  }
  
  // 5. 触发自定义事件通知外部状态变化
  this.$emit('updated', this.getLatestData());
}

总结对比

特性 beforeUpdate updated
执行时机 DOM更新前 DOM更新后
数据状态 已更新 已更新
DOM状态 旧DOM 新DOM
修改数据 谨慎使用 极不推荐
主要用途 获取更新前状态、准备操作 DOM相关操作、第三方库更新
执行频率 每次数据变化 每次数据变化

卸载

卸载阶段是组件从DOM中移除、清理资源的过程,主要包括两个关键钩子函数

beforeUnmount (Vue 3) / beforeDestroy (Vue 2)

  1. 时机:组件卸载前调用,实例仍然完全可用。

  2. 特点

    • 组件实例仍完全可用
    • 可以访问data、methods等
    • 适合清理资源
    • 组件还未销毁
  3. 常用场景

javascript 复制代码
// Vue 3 Composition API
onBeforeUnmount(() => {
  // 1. 清除定时器
  clearInterval(this.timer);
  clearTimeout(this.timeout);
  
  // 2. 取消网络请求
  if (this.pendingRequest) {
    this.pendingRequest.cancel();
  }
  
  // 3. 移除全局事件监听
  window.removeEventListener('resize', this.handleResize);
  document.removeEventListener('click', this.handleClick);
  
  // 4. 销毁第三方库实例
  if (this.chart) {
    this.chart.dispose();
  }
  
  // 5. 取消订阅
  this.$bus.off('event', this.handleEvent);
})

// Vue 2 Options API
beforeDestroy() {
  // 1. 清除定时器
  clearInterval(this.timer);
  
  // 2. 取消网络请求
  if (this.pendingRequest) {
    this.pendingRequest.cancel();
  }
  
  // 3. 移除全局事件监听
  window.removeEventListener('resize', this.handleResize);
}

unmounted (Vue 3) / destroyed (Vue 2)

  1. 时机:组件卸载后调用,此时组件实例已被销毁。

  2. 特点

    • 组件实例已被销毁
    • 所有指令解绑
    • 所有事件监听已移除
    • 无法访问组件数据和方法
  3. 常用场景

javascript 复制代码
// Vue 3 Composition API
onUnmounted(() => {
  // 1. 最终的清理确认
  console.log('组件已卸载');
  
  // 2. 触发外部通知
  this.$emit('destroyed');
  
  // 3. 记录日志
  console.log('组件销毁完成', this.$options.name);
})

// Vue 2 Options API
destroyed() {
  // 1. 最终的清理确认
  console.log('组件已销毁');
  
  // 2. 触发外部通知
  this.$emit('destroyed');
  
  // 3. 清理DOM引用
  this.$refs = {};
}

总结对比

特性 beforeUnmount/beforeDestroy unmounted/destroyed
执行时机 卸载前 卸载后
实例状态 完全可用 已销毁
访问data ✅ 可访问 ❌ 不可访问
访问methods ✅ 可调用 ❌ 不可调用
主要用途 清理资源、取消订阅 最终确认、日志记录
事件监听 可移除 已自动移除

特殊钩子函数

activated

  1. 时机:被keep-alive缓存的组件激活时调用。

  2. 特点

    • 组件从缓存中重新激活
    • 适用于频繁切换的组件
    • 可替代mounted的部分功能
  3. 常用场景

javascript 复制代码
activated() {
  // 1. 刷新数据
  this.refreshData();
  
  // 2. 恢复状态
  this.restoreState();
  
  // 3. 重新添加事件监听
  window.addEventListener('scroll', this.handleScroll);
}

deactivated

  1. 时机:被keep-alive缓存的组件停用时调用。

  2. 特点

    • 组件被缓存而非销毁
    • 组件实例仍保留
    • 适合暂停操作而非清理
  3. 常用场景

javascript 复制代码
deactivated() {
  // 1. 暂停视频播放
  this.pauseVideo();
  
  // 2. 保存当前状态
  this.saveState();
  
  // 3. 移除临时事件监听
  window.removeEventListener('scroll', this.handleScroll);
}

errorCaptured

  1. 时机:捕获后代组件错误时调用。

  2. 特点

    • 可捕获子组件、孙组件的错误
    • 返回false可阻止错误继续传播
    • 可用于错误处理和上报
  3. 常用场景

javascript 复制代码
errorCaptured(err, vm, info) {
  // 1. 错误日志上报
  this.logErrorToServer(err, info);
  
  // 2. 显示错误提示
  this.errorMessage = '组件加载失败';
  
  // 3. 阻止错误继续传播
  return false;
}

完整生命周期对比表

阶段 Vue 2 Vue 3 (Options) Vue 3 (Composition) 主要用途
创建 beforeCreate beforeCreate setup() 初始化前
创建 created created setup() 初始化完成
挂载 beforeMount beforeMount onBeforeMount 挂载前准备
挂载 mounted mounted onMounted DOM操作、请求
更新 beforeUpdate beforeUpdate onBeforeUpdate 更新前状态获取
更新 updated updated onUpdated 更新后DOM操作
卸载 beforeDestroy beforeUnmount onBeforeUnmount 清理资源
卸载 destroyed unmounted onUnmounted 销毁确认
缓存 activated activated onActivated 缓存激活
缓存 deactivated deactivated onDeactivated 缓存停用
错误 errorCaptured errorCaptured onErrorCaptured 错误处理
相关推荐
蓝莓味的口香糖20 小时前
【vue3】组件的批量全局注册
前端·javascript·vue.js
独泪了无痕21 小时前
自动导入 AutoImport:告别手动引入依赖,优化Vue3开发体验
前端·vue.js·typescript
全栈小51 天前
【前端】Vue 组件开发中的枚举值验证:从一个Type属性错误说起
前端·javascript·vue.js
꧁꫞꯭零꯭点꯭꫞꧂1 天前
G6绘制机柜 以及机柜设备的demo
前端·javascript·vue.js
wuhen_n1 天前
5年前端,我为什么要all in AI Agent?
前端·vue.js·ai编程
optimistic_chen1 天前
【Vue入门】创建Vue工程环境和响应式函数
前端·javascript·vue.js·前端框架·html
林恒smileZAZ1 天前
告别满屏 v-if:用一个自定义指令搞定 Vue 前端权限控制
前端·javascript·vue.js
AI论文酱1 天前
Vue.js入门(搭建第一个页面,新手零配置)
vue.js
SuperEugene1 天前
NPM Script 实战:常用命令设计与封装|Vue 工程化篇
前端·javascript·vue.js·前端框架·npm
小霍同学1 天前
Vue 动态表单(Dynamic Form)
前端·vue.js