前言
Hello~大家好。我是秋天的一阵风
在 Vue 的世界里,生命周期钩子是每个组件成长的见证。从组件的出生到消逝,每个阶段都有特定的钩子,让我们可以洞察并参与组件的每一个重要时刻。但是,当被问到 "如何监听这些生命周期事件" 这个问题时,你是否能迅速回答出来?或者,你是否突然感到有些迷茫?
在我们揭晓答案之前,让我们先简单回顾一下 Vue 2
和 Vue 3
的生命周期知识。这将帮助我们更好地理解如何监听这些关键的生命周期事件。
一、Vue2 与 Vue3 生命周期的区别
Vue 2 生命周期钩子 | Vue 3 生命周期钩子 | 描述 |
---|---|---|
beforeCreate |
无直接对应 | 在 Vue 3 中,beforeCreate 的功能被 setup() 钩子覆盖。在 setup() 中,你可以访问到 props 和 context ,但不能访问到 this 。 |
created |
setup() |
在 Vue 3 中,created 的功能被 setup() 钩子覆盖。在 setup() 中,你可以访问到 props 和 context ,但不能访问到 this 。 |
beforeMount |
onBeforeMount |
在组件挂载到 DOM 之前调用。 |
mounted |
onMounted |
在组件挂载完成后调用。 |
beforeUpdate |
onBeforeUpdate |
在组件即将更新之前调用。 |
updated |
onUpdated |
在组件更新后调用。 |
beforeDestroy |
onBeforeUnmount |
在组件即将卸载之前调用。 |
destroyed |
onUnmounted |
在组件卸载后调用。 |
errorCaptured |
onErrorCaptured |
当捕获一个来自子孙组件的错误时被调用。 |
🎯 关于
errorCaptured
生命周期
errorCaptured
是一个相对冷门但极其强大的生命周期钩子,它允许你在组件及其子组件中捕获未处理的错误。这对于全局错误监控和自定义错误处理策略非常有用。如果你对这个钩子感兴趣,强烈推荐你阅读以下文章,深入了解其工作原理和应用场景:
这篇文章详细介绍了
errorCaptured
的定义、参数、应用场景以及它的局限性。通过阅读这篇文章,> 你将了解如何在项目中有效利用这一钩子。🔎 深入 Vue 3 生命周期的源码实现
如果你对 Vue 3 生命周期的源码实现感兴趣,或者想了解 Vue 3 生命周期钩子的执行过程,以下文章将为你揭开神秘的面纱:
这篇文章深入探讨了 Vue 3 生命周期钩子的注册和执行机制,包括
onBeforeMount
、onMounted
、>onBeforeUpdate
、onUpdated
、onBeforeUnmount
和onUnmounted
等钩子的实现细节。
除此之外,Vue.js 3.0
还新增了两个用于调试的生命周期 API:onRenderTracked
和 onRenderTriggered
。
更多的生命周期API信息你可以在这里阅读:组合式API:生命周期钩子
二、Vue2中监听生命周期
我们来看一个简单的例子,下面代码例子中注册了多个生命周期方法,在组件对应的生命周期中会执行。
html
<template>
<div>
<h1>Vue 2 生命周期示例</h1>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
message: "Hello Vue 2",
};
},
beforeCreate() {
console.log("beforeCreate: 实例刚刚被创建,data 和 methods 还未初始化");
},
created() {
console.log("created: 实例创建完成,data 和 methods 已初始化");
},
beforeMount() {
console.log("beforeMount: 挂载开始之前,模板已编译,但尚未挂载到 DOM");
},
mounted() {
console.log("mounted: 挂载完成,模板已渲染到 DOM");
},
beforeUpdate() {
console.log("beforeUpdate: 数据更新之前,虚拟 DOM 还未更新");
},
updated() {
console.log("updated: 数据更新完成,虚拟 DOM 和真实 DOM 都已更新");
},
beforeDestroy() {
console.log("beforeDestroy: 实例销毁之前,组件仍然可用");
},
destroyed() {
console.log("destroyed: 实例销毁完成,组件已不可用");
},
errorCaptured(err, vm, info) {
console.error("errorCaptured: 捕获来自子组件的错误");
console.error("Error:", err);
console.error("Component:", vm);
console.error("Error Info:", info);
return false; // 返回 false 可以阻止错误继续向上冒泡
},
};
</script>
<script>
export default {
components: {},
};
</script>
在开发过程中,我们常常会发现业务逻辑分散在各个生命周期钩子中,这种分散的代码结构有时会降低代码的可读性,尤其是当业务逻辑复杂且代码量较大时。这种情况下,代码的维护和理解成本会显著增加。
为了解决这一问题,我们可以巧妙地利用 Vue 提供的 hook:
语法来集中管理某一块的业务逻辑。通过这种方式,我们可以将相关的业务逻辑集中到一个特定的生命周期钩子中,从而让代码结构更加清晰,逻辑更加连贯,显著提升代码的可读性和可维护性。
1.this.$on("hook:mounted")
用法
html
<template>
<div>
<h1>Vue 2 生命周期示例</h1>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
message: "Hello Vue 2",
};
},
created() {
console.log("created: 实例创建完成,data 和 methods 已初始化");
this.$on("hook:mounted", () => {
console.log("mounted 挂载触发")
});
this.$on("hook:updated", () => {
// 挂载时执行一些业务A相关逻辑;
});
},
};
</script>
<script>
export default {
components: {},
};
</script>
2. @hook
监听子组件生命周期
那如果我想监听一个组件的生命周期呢?其实也是可以的。
我们可以直接用@hook
来监听子组件的生命周期
js
<template>
<div>
<h1>Vue 2 生命周期示例</h1>
<button @click="handleClick()">
{{ show ? "销毁子组件" : "展示子组件" }}
</button>
<ChildComponent
v-if="show"
@hook:mounted="handleChildMounte"
@hook:destroyed="handleChildDestroyed"
/>
</div>
</template>
<script>
import ChildComponent from "./ChildComponent.vue";
export default {
name: "App",
components: {
ChildComponent,
},
data() {
return {
show: false,
};
},
methods: {
handleClick() {
this.show = !this.show;
},
handleChildMounte() {
console.log("子组件挂载完成");
},
handleChildDestroyed() {
console.log("子组件销毁完成");
},
},
};
</script>
<style scoped>
click-btn {
padding: 10px 20px;
background-color: #333;
color: #fff;
border: 1px solid #333;
cursor: pointer;
}
</style>
js
// ChildComponent.vue
<template>
<div>
<h2>我是子组件</h2>
</div>
</template>
<script>
export default {
methods: {},
};
</script>
三、Vue3中监听生命周期
Vue3中只需要将hook
替换为vue
即可,我们看看代码和效果:
js
<template>
<div>
<h1>Vue 3 生命周期示例</h1>
<button @click="handleClick" class="click-btn">
{{ show ? "销毁子组件" : "展示子组件" }}
</button>
<ChildComponent
v-if="show"
@vue:mounted="handleChildMounted"
@vue:unmounted="handleChildUnmounted"
/>
</div>
</template>
<script>
import { ref } from "vue";
import ChildComponent from "./ChildComponent.vue";
export default {
name: "App",
components: {
ChildComponent,
},
setup() {
const show = ref(false);
const handleClick = () => {
show.value = !show.value;
};
const handleChildMounted = () => {
console.log("子组件挂载完成");
};
const handleChildUnmounted = () => {
console.log("子组件销毁完成");
};
return {
show,
handleClick,
handleChildMounted,
handleChildUnmounted,
};
},
};
</script>
<style scoped>
.click-btn {
padding: 10px 20px;
background-color: #333;
color: #fff;
border: 1px solid #333;
cursor: pointer;
}
</style>
🚀🚀🚀
更多详细内容,你可以查看官方的迁移指南: Vue3迁移指南VNode 生命周期事件