一、创建阶段,beforeCreate 和 created 到底能干啥?
p>想学Vue2但被生命周期钩子搞晕?看着created、mounted这些名词一头雾水,不知道每个阶段干啥、怎么结合业务场景用?别慌,这篇文章把Vue2生命周期钩子拆成「创建→挂载→更新→销毁」四个核心阶段,再补充场景化钩子,用大白话+例子讲清楚每个钩子的作用、什么时候用,帮你从「背概念」到「会实操」~
Vue 实例从 new Vue()
开始,先进入创建阶段,这一步是给实例“搭骨架”,决定后续能调用哪些数据和方法。
-
beforeCreate:实例刚初始化,相当于“地基刚打好,内部线路还没铺”。
data
里的变量、methods
里的方法都没绑定到实例上,你打印this.xxx
全是undefined
,这一步基本用不上,了解时机即可。 -
created:实例完成“数据观测(把
data
变响应式)、事件配置”,相当于“房子水电通了,能住人了”。this
能访问data
和methods
,是初始化数据的黄金时机——比如页面加载时发 Ajax 请求、初始化全局变量。
举个栗子:做个人中心页面,需要加载用户头像、昵称,在 created
里调接口最安全:
export default { data() { return { userInfo: {} } }, created() { this.fetchUserInfo() }, // 能拿到 this,调用 methods methods: { fetchUserInfo() { axios.get('/api/user').then(res => { this.userInfo = res.data; // data 已被代理,能直接赋值 }); } } };
为啥不在 beforeCreate
发请求?因为那时候 this.userInfo
都没绑定,调方法也会报错,created
是初始化数据的关键节点~
挂载阶段:beforeMount 和 mounted 怎么玩 DOM?
创建阶段结束后,Vue 要把模板(template
)转换成真实 DOM 并渲染到页面,这就是挂载阶段。
-
beforeMount:模板已编译成渲染函数,但 DOM 还没真正渲染到页面,此时页面上对应的 DOM 还是“虚拟”的,操作 DOM 没意义,所以这个钩子用得少,理解“准备挂载前的过渡”即可。
-
mounted:真实 DOM 已渲染完成,
$el
(Vue 实例对应的 DOM 元素)也存在了,这一步是操作真实 DOM 的安全区——比如初始化第三方插件(ECharts、富文本编辑器)、修改 DOM 样式/内容。
举个例子:做带进度条的组件,必须等 mounted
才能拿到 DOM 节点:
export default { data() { return { progress: 0 } }, mounted() { const progressBar = this.$el.querySelector('.progress-bar'); // 模拟进度条加载 const timer = setInterval(() => { this.progress += 10; progressBar.style.width = this.progress + '%'; if (this.progress >= 100) clearInterval(timer); }, 500); } };
如果在 beforeMount
里写这段代码,根本找不到 .progress-bar
节点,因为 DOM 还没渲染~
更新阶段:beforeUpdate 和 updated 咋应对数据变化?
Vue 是响应式框架,数据变了页面会自动更新。更新阶段就是处理“数据变化→页面更新”的钩子。
-
beforeUpdate:数据已经改变,但 DOM 还没更新。
this
里的数据是新的,页面显示的却是旧的,这个钩子适合“DOM 更新前记录旧状态”(实际用得少,主要是理解时机)。 -
updated:数据和 DOM 都完成更新,页面内容和
data
完全同步,这一步适合“DOM 更新后必须执行的操作”,比如统计元素位置、加动画收尾。
举个电商场景:购物车数量变化后,给数字加弹跳动画:
export default { data() { return { cartCount: 0 } }, methods: { addToCart() { this.cartCount += 1; } // 数据变化,触发更新 }, updated() { const cartBadge = this.$el.querySelector('.cart-badge'); cartBadge.classList.add('bounce'); // DOM 已更新,加动画 setTimeout(() => { cartBadge.classList.remove('bounce'); }, 500); } };
如果在 beforeUpdate
里加动画,DOM 还是旧的,数字没变化,动画就白加了。updated
是数据和 DOM 同步后的“操作安全区”~
销毁阶段:beforeDestroy 和 destroyed 咋“善后”?
当 Vue 实例被销毁(比如路由跳转、组件被 v-if
移除),进入销毁阶段,这一步要做“清理工作”,防止内存泄漏。
-
beforeDestroy:实例还没销毁,所有数据、方法都能用,此时要“清除副作用”——比如清定时器、解绑自定义事件、取消 Axios 请求。
-
destroyed:实例完全销毁,所有数据绑定、事件监听都被移除,这一步用得少,因为清理工作一般在
beforeDestroy
做,destroyed
更多是“确认销毁完成”的通知。
举个定时器的例子,不清理会内存泄漏:
export default { data() { return { timer: null } }, mounted() { this.timer = setInterval(() => { console.log('每隔1秒执行'); }, 1000); }, beforeDestroy() { clearInterval(this.timer); // 销毁前清定时器,否则会一直跑 this.timer = null; } };
如果跳过 beforeDestroy
直接销毁,定时器会持续占用内存,页面越用越卡~
额外钩子:activated、deactivated、errorCaptured 是干啥的?
除了核心的 8 个钩子(创建 2 + 挂载 2 + 更新 2 + 销毁 2),Vue2 还有几个“场景化钩子”,针对性解决特定问题。
activated / deactivated(和 keep-alive 配合)
只有组件被 <keep-alive>
包裹时才会触发:
- activated:组件从缓存中取出、重新显示时调用,适合“缓存组件切换后刷新数据”,Tab 切换时重新拉取当前 Tab 数据。
- deactivated:组件被缓存(离开页面但没销毁)时调用,适合“暂停定时器、停止轮播”等临时暂停操作。
举个 Tab 切换的例子:
export default { activated() { this.fetchTabData(); }, // 切回 Tab 时刷新数据 deactivated() { clearInterval(this.timer); } // 离开时暂停定时器 };
errorCaptured(错误捕获)
当组件树中某个组件抛出错误时触发,能捕获子组件的错误,返回 false
可阻止错误向上传播,适合做全局错误监控,比如记录错误信息、上报服务器。
示例:
export default { errorCaptured(err, instance, info) { // err:错误对象;instance:出错的组件实例;info:错误发生的钩子(如 mounted) console.log('捕获到错误:', err, '在组件:', instance, '钩子:', info); return false; // 阻止错误向上冒泡 } };
生命周期执行顺序总结(附“人生 analogy”)
把 Vue 实例的生命周期想象成“出生→长大→变化→死亡”,执行顺序是:
beforeCreate
(刚孕育)→ created
(五脏俱全)→ beforeMount
(穿衣服准备出门)→ mounted
(正式出门,能互动)→(数据变化时)beforeUpdate
(换衣服前)→ updated
(换好衣服)→(实例销毁时)beforeDestroy
(临终前交代后事)→ destroyed
(尘归尘)
记住这个顺序,写代码时就能精准判断“哪一步该做什么”~
新手常踩的坑:这些场景别用错钩子!
理解时机是基础,避开这些坑才能写出健壮的代码:
- 在 beforeCreate 里操作 data/methods → 必错!此时数据还没绑定,
this.xxx
全是undefined
。 - mounted 里拿不到 DOM 元素 → 检查是不是异步渲染?比如子组件没加载完、DOM 被
v-if
控制(v-if
为false
时 DOM 不存在),可以用$nextTick
延迟执行:mounted() { this.$nextTick(() => { const el = this.$el.querySelector('.async-el'); // 确保 DOM 完全渲染 }); }
- 忘记在 beforeDestroy 清理资源 → 定时器、自定义事件(如
window.addEventListener
)不清理,会导致内存泄漏,页面越用越卡。 - 把 mounted 当“整个页面加载完成” →
mounted
只代表当前组件的 DOM 渲染完成,不是整个页面,如果要等所有资源加载完,得用window.onload
或全局钩子。
掌握生命周期,写出更“丝滑”的 Vue 代码
Vue2 生命周期钩子的本质,是在实例的不同阶段“插桩”,让你精准控制“什么时候做什么事”,理解每个钩子的执行时机,结合业务场景(比如初始化数据→created
,操作 DOM→mounted
,清资源→beforeDestroy
),代码就会更高效、更少 Bug。
现在再看 created
、mounted
这些钩子,是不是清晰多了?下次写组件时,先想“这个逻辑该在哪个阶段执行”,按阶段做事,Vue 开发就会顺很多~
如果还有疑问(多个组件嵌套时生命周期执行顺序是啥?”“keep-alive 钩子怎么和核心钩子配合?”),留言告诉我,下次展开讲~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。