vue的生命周期

一、总体时间线(一张图记一辈子)

二、四大阶段 8 个场景逐条拆解

阶段 1:实例创建(Initialization)

钩子触发时机能做的事不能做的事源码位置(vue2)常见坑
beforeCreate实例刚 new 完,inject、props、methods、data、computed、watch 全部未初始化可以:打印 this,看到裸实例;注册全局事件总线不能:访问 this.xxx、this.$data、DOMcore/instance/init.js -> initLifecycle试图读取 data 得到 undefined
setup() (仅 Vue3)组件实例尚未创建,但 props 已解析可以:使用 ref/reactive 创建响应式数据、调用组合式函数不能:使用 this(不存在);访问 DOMruntime-core/component.ts忘记 return 模板需要的绑定
created完成了数据观测、computed、methods、watch 的初始化,但 $el 尚不可用可以:发 ajax,访问 data/props/computed;写 this.xxx不能:访问 DOM($el 为 undefined)core/instance/init.js -> callHook在 SSR 中此阶段 DOM 仍未创建

调试技巧

// main.js (Vue2)
console.log('new Vue 前', Date.now());
new Vue({
  beforeCreate() { debugger; },   // Chrome 停在这里,看 call stack
  created()      { console.log('$el:', this.$el); /* undefined */ }
})

阶段 2:模板编译 + DOM 挂载(Mounting)

钩子触发时机能做的事不能做的事源码位置常见坑
beforeMount模板/渲染函数已编译,但虚拟 DOM 第一次 patch 前可以:最后一次修改不触发额外渲染的数据不能:访问真实 DOM;读取 $refscore/instance/lifecycle.js -> mountComponent用 $refs 会得到 undefined
mounted真实 DOM 已插入页面,$el 已指向元素可以:操作 DOM、第三方库初始化、拿 $refs不能:保证所有子组件也 mounted(异步子组件可能还没好)同上父 mounted 时子组件不一定 mounted

可视化验证

<template>
  <div ref="box">hello</div>
</template>
<script>
export default {
  beforeMount() { console.log('beforeMount', this.$refs.box); /* undefined */ },
  mounted()     { console.log('mounted', this.$refs.box);     /* <div> */ }
}
</script>

阶段 3:响应式更新(Updating)

钩子触发时机能做的事不能做的事源码位置常见坑
beforeUpdate数据已变,虚拟 DOM 打补丁前可以:访问现有 DOM 状态(旧值)建议:不要改数据,会触发二次更新core/observer/scheduler.js -> flushSchedulerQueue死循环:此处改同一响应式属性
updatedDOM 已打补丁完成可以:操作更新后的 DOM不能:改数据后直接读 DOM(DOM 可能还没 flush 完)同上在 updated 里再改数据 → 无限循环

死循环 DEMO

export default {
  data: () => ({ n: 0 }),
  updated() {
    this.n++;   // ❌ 无限递归
  }
}

解决:用 nextTick 或 watch 替代。

阶段 4:卸载(Unmount / Teardown)

钩子触发时机能做的事不能做的事备注
beforeUnmount(Vue3) / beforeDestroy(Vue2)组件即将被卸载可以:清理定时器、取消订阅、解绑全局事件不能:访问 DOM 已卸载的子组件Vue3 改名更语义化
unmounted(Vue3) / destroyed(Vue2)组件完全卸载,所有指令、事件监听器已解绑可以:记录日志不能:访问实例上的响应式数据(已解除绑定)keep-alive 缓存的组件不会触发

组合式清理示例

import { onBeforeUnmount, onUnmounted } from 'vue';
export default {
  setup() {
    const timer = setInterval(() => {}, 1000);
    onBeforeUnmount(() => clearInterval(timer));
    onUnmounted(() => console.log('组件已销毁'));
  }
}

三、keep-alive 专属钩子

Vue2Vue3触发时机
activatedonActivated被 keep-alive 缓存的组件再次显示
deactivatedonDeactivated被 keep-alive 缓存的组件隐藏

使用场景:在列表页缓存滚动位置、停止/恢复定时器。

四、调试与可视化

  1. Chrome DevTools → Sources → 在生命周期钩子中写 debugger;

  2. 安装 Vue Devtools → Timeline 面板直接看生命周期火焰图

  3. Vue3 的 setup() 中可加 console.trace() 查看调用栈

五、面试高频追问

问题一句话回答
为什么 beforeCreate 拿不到 data?此时 initState 尚未执行,data 未代理到 vm。
created 里能操作 DOM 吗?不能,$el 还是 undefined。
父 mounted 时子组件 mounted 了吗?不一定,子组件可以是异步组件。
updated 里再改同一份数据会怎样?再次触发 flush,导致无限循环。
Vue3 的 setup 对应 Vue2 的哪两个钩子?同时替代了 beforeCreate 和 created。

六、完整可运行 DEMO(Vue3 组合式)

<script type="module">
import { createApp, ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js';

createApp({
  template: `
    <button @click="count++">count: {{ count }}</button>
  `,
  setup() {
    const count = ref(0);

    console.log('setup');
    onBeforeMount(() => console.log('onBeforeMount'));
    onMounted(()   => console.log('onMounted'));
    onBeforeUpdate(() => console.log('onBeforeUpdate'));
    onUpdated(()    => console.log('onUpdated'));
    onBeforeUnmount(() => console.log('onBeforeUnmount'));
    onUnmounted(()      => console.log('onUnmounted'));

    return { count };
  }
}).mount('#app');
</script>

<div id="app"></div>

打开浏览器控制台,点击按钮即可看到完整生命周期日志。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值