阅读视图

发现新文章,点击刷新页面。

深度解析vue的生命周期

概述

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

生命周期图示

image.png

创建

  • 初始化组件的选项(data、methods、computed 等)
  • 建立响应式数据系统
beforeCreate
  1. 时机:实例初始化之后,数据观测和事件配置之前
    DOM正在构建/已完成,CSSOM可能尚未完成
  2. 特点:无法访问到 datacomputedmethods 等
    可以访问this但值为空对象
  3. 常用场景:
created
  1. 时机:模板编译/挂载之前,初始化选项API之后
  2. 特点:可以访问 datacomputedmethods
    模板还未编译,$el 属性还不存在
  3. 常用场景:异步请求、数据初始化
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. 常用场景:
beforeMount() {
  // 1. 最后一次数据修改机会(不会触发重渲染)
  this.someData = this.processData(this.someData);
  
  // 2. 初始化一些不依赖DOM的配置
  this.initConfig();
  
  // 3. 服务端渲染(SSR)中唯一可用的挂载阶段钩子
}

mounted

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

  2. 特点:

  • 真实DOM已生成并插入页面
  • 可访问和操作DOM元素
  • 可访问子组件
  • 不保证所有子组件都已挂载(需使用$nextTick)
  1. 常用场景:
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. 常用场景:

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. 常用场景:

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. 常用场景

// 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. 常用场景

// 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. 常用场景

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

deactivated

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

  2. 特点

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

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

errorCaptured

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

  2. 特点

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

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 错误处理
❌