Vue.js 是一个流行的前端框架,其实例具有一系列的生命周期钩子,这些钩子允许开发者在特定时间点对其进行干预操作。下面是Vue实例生命周期的详细说明:
1.beforeCreate
总述:这是Vue实例的第一个生命周期钩子,在此阶段,数据观察和事件/侦听器的初始化还未开始。
beforeCreate
是 Vue 实例的生命周期钩子之一,它发生在 Vue 实例开始初始化之后,但在实例创建完成之前。在这个阶段,数据观察、事件和生命周期钩子还未初始化,所以 this
上面不会有响应式数据,即 data
和 methods
上的方法和数据都无法访问。
下面是 beforeCreate
钩子的一些重要特点:
-
无法访问响应式数据:此时 Vue 实例的
data
和methods
还没有初始化,因此在beforeCreate
钩子中无法访问到这些响应式数据。 -
事件监听器未设置:Vue 实例的事件监听器也还没有设置,所以不能使用
this.$on
、this.$emit
等方法。 -
依赖注入尚未设置:如果使用了依赖注入(provide/inject),在
beforeCreate
钩子中,这些依赖还无法使用,因为它们也还未被初始化。 -
不涉及DOM:因为此阶段 Vue 实例还没有挂载,所以
beforeCreate
也无法访问到this.$el
。
由于在 beforeCreate
钩子中,实例的大部分功能尚未可用,这个生命周期的钩子用得比较少。然而,它仍然有其用武之地,比如:
-
初始化非响应式属性:可以在这个钩子中初始化一些实例的属性,这些属性不需要是响应式的。例如,可以设置一些默认的配置。
-
配置插件或库:如果需要在 Vue 创建之前进行一些全局配置,比如配置一个不需要响应式数据的插件,可以在
beforeCreate
钩子中进行。
下面是一个简单的 beforeCreate
使用示例:
new Vue({
data: () => ({
someData: 'Vue'
}),
beforeCreate: function () {
console.log('beforeCreate: this.someData =', this.someData); // undefined
// 此时 data 和 methods 上的数据和方法都无法访问
this.myProperty = 'Initial Value'; // 可以添加非响应式属性
},
created: function () {
console.log('created: this.someData =', this.someData); // "Vue"
// 此时已经可以访问到响应式数据 someData
}
}).$mount('#app');
在 beforeCreate
钩子中,this.someData
访问不到数据,因为此时 data
对象还没被初始化。但是在 created
钩子中,就可以正常访问 someData
了。我们在 beforeCreate
钩子中添加的 myProperty
属性是非响应式的,因为它不是在 data
选项中声明的。
2.created
总述:在此阶段,Vue实例已完成以下配置:数据观察、属性和方法的运算、watch/event 事件回调。然而,挂载阶段还没开始,$el
属性目前不可见。
created
是 Vue 实例的生命周期钩子之一,它在实例创建完成后被调用。在这个阶段,Vue 实例已经完成了数据观察(响应式系统)、属性和方法的运算,以及事件监听器的设置。然而,此时的 Vue 实例还未进行DOM挂载,也就是说 $el
属性还不可用。
以下是 created
钩子的一些重要特点:
-
访问响应式数据:此时,Vue 实例的
data
和methods
已经创建和初始化,因此可以访问或修改这些响应式数据。 -
事件监听器已设置:
created
钩子中,Vue 实例的事件监听器已经设置好了,因此可以使用像this.$on
和this.$emit
这样的事件方法。 -
依赖注入已可用:如果使用了依赖注入(provide/inject),到了
created
钩子,这些依赖已经可以使用。 -
不涉及DOM操作:在
created
钩子中,Vue 实例还没有挂载到DOM上,因此无法访问到this.$el
。
created
钩子通常用于以下场景:
-
数据初始化:可以在这个钩子中进行数据的初始化操作,如发起 AJAX 请求,从后端获取数据,然后用这些数据初始化组件的状态。
-
事件监听与订阅:由于此时事件监听器已经设置好,可以进行事件订阅或执行其他需要事件监听器的操作。
-
依赖注入的使用:如果组件使用了依赖注入,可以在
created
钩子中安全地使用这些依赖。
下面是一个 created
钩子的示例:
new Vue({
data: () => ({
someData: 'Hello Vue'
}),
created: function () {
console.log('created: this.someData =', this.someData); // "Hello Vue"
// 此时已经可以访问到响应式数据 someData
this.fetchData(); // 可以执行数据初始化等操作
},
methods: {
fetchData: function() {
// 假设这是一个获取数据的方法
// 在此处发起AJAX请求或进行其他数据初始化操作
}
}
}).$mount('#app');
在这个示例中,created
钩子被用来访问初始化的数据 someData
并调用一个方法 fetchData
来模拟从服务器获取数据。因为此时所有的响应式数据和方法都已经准备好了,所以这些操作可以安全地进行。
3.beforeMount
总述:在beforeMount
阶段发生在模板编译成渲染函数的过程之后,但是在它挂载到DOM上之前。此时,可以对渲染前的DOM进行最后的访问,但是此时的DOM不会有任何数据被渲染进去。
beforeMount
是 Vue 实例的生命周期钩子之一。它在 created
钩子之后、mounted
钩子之前被调用,即在模板编译/渲染成 HTML 之后,但在挂载到 DOM 上之前。在这个阶段,Vue 实例的 el
属性已经创建,但尚未替换成渲染好的 DOM。
以下是 beforeMount
钩子的一些重要特点:
-
DOM 尚未更新:
beforeMount
钩子执行时,Vue 实例已经编译了模板,但是生成的 DOM 还未挂载到页面上。 -
实例属性可用:由于在
beforeCreate
和created
钩子之后,Vue 实例的响应式数据、计算属性、方法等都已经可用,因此在beforeMount
中可以自由地使用这些属性。 -
一次性钩子:除非 Vue 实例被重新渲染(例如使用
v-if
),beforeMount
通常只调用一次。
beforeMount
钩子通常用于以下场景:
-
执行依赖于模板的操作:如果需要在模板渲染到 DOM 之前执行一些操作,可以在
beforeMount
中进行。但通常情况下,很少需要在挂载之前操作模板。 -
服务器端渲染(SSR)中的客户端激活(hydration):在 SSR 中,
beforeMount
钩子将在客户端激活过程中调用。服务器生成的 HTML 将被客户端的 Vue 实例接管激活。
下面是一个简单的 beforeMount
钩子示例:
new Vue({
el: '#app',
data: () => ({
message: 'Vue 生命周期'
}),
beforeMount: function () {
console.log('beforeMount: 此时模板已编译但未挂载');
// 我们可以访问到响应式数据 `message`,但 DOM 还未更新
console.log('beforeMount: this.message =', this.message);
},
mounted: function () {
console.log('mounted: 此时模板已挂载到 DOM');
// 此时 DOM 已经包含了渲染后的数据
console.log('mounted: this.$el.textContent =', this.$el.textContent);
}
});
// 在浏览器控制台中,这将按顺序输出:
// "beforeMount: 此时模板已编译但未挂载"
// "beforeMount: this.message = Vue 生命周期"
// "mounted: 此时模板已挂载到 DOM"
// "mounted: this.$el.textContent = Vue 生命周期"
在这个示例中,beforeMount
钩子被用来输出一个日志,说明此时模板已编译但还未挂载。在这个钩子中,数据 message
已经可用,但实际的 DOM 还没有更新为最终的渲染结果。随后,mounted
钩子被调用,此时可以访问到更新后的 DOM。
4.mounted
总述:在mounted
阶段,Vue实例被挂载到指定的DOM元素上。这个时候,可以访问到更新后的DOM(例如,可以操作DOM,绑定DOM事件)。
mounted
是 Vue 实例的生命周期钩子之一。该钩子在实例被挂载到 DOM 之后被调用,此时,创建的 Vue 实例或组件的模板已经编译成了 HTML,并替换了 el
属性指定的 DOM 元素。在执行 mounted
钩子时,可以获取和操作 DOM 元素及其子元素,因为它们都已经被渲染和挂载在页面上。
以下是 mounted
钩子的一些重要特点:
-
DOM 可访问:在这个生命周期阶段,组件的 DOM 已经完成渲染并被挂载到了页面上,因此可以执行 DOM 操作。
-
子组件可能尚未挂载:虽然当前组件的 DOM 已经渲染,但并不保证所有子组件也都已经完成挂载,因为 Vue 实例的挂载是异步的。
-
适合执行依赖 DOM 的操作:例如,可能想在这个生命周期钩子中集成第三方库(如滑动库或图表库),因为此时可以保证 DOM 元素的存在。
mounted
钩子通常用于以下场景:
-
操作 DOM:可以安全地操纵 DOM 元素,例如添加事件监听器或使用 jQuery 等库。
-
发送 AJAX 请求:虽然通常建议在
created
钩子中进行 AJAX 请求,以避免不必要的 DOM 重绘,但在某些情况下,如果你的 AJAX 请求依赖于 DOM (例如,获取元素的尺寸来决定请求数据的数量),那么可以在mounted
钩子中进行。 -
集成非响应式的库:如果需要集成非 Vue 的库,通常需要等到 DOM 完全渲染后才能正确初始化这些库,
mounted
是一个很好的时机。
下面是一个 mounted
钩子的示例:
new Vue({
el: '#app',
data: () => ({
message: 'Hello, Vue!'
}),
mounted: function () {
console.log('mounted: 组件已挂载到 DOM');
// 此刻可以访问到 DOM 元素
this.$nextTick(function () {
// 保证此回调在 DOM 完全渲染后执行
console.log('mounted: this.$el.textContent =', this.$el.textContent);
});
}
});
// 控制台输出:
// "mounted: 组件已挂载到 DOM"
// "mounted: this.$el.textContent = Hello, Vue!"
在这个示例中,mounted
钩子用来在控制台中输出确认信息,表明组件已经挂载。然后使用 this.$nextTick
来确保在 DOM 完全更新后执行回调函数,这个技巧常用于确保访问的是最终渲染的结果。
需要注意的是,如果正在进行服务器端渲染(SSR),mounted
钩子只会在客户端执行。因此,任何只在客户端执行的代码,例如与浏览器 API 相关的代码,都应该放在 mounted
钩子中。
5.beforeUpdate
总述:当数据变化导致虚拟DOM重新渲染和打补丁之前被调用。在这个钩子中,可以访问现有的DOM,就是即将更新之前的DOM状态。
beforeUpdate
是 Vue 实例的生命周期钩子之一。它在 Vue 实例的响应式数据发生变化,且 DOM 重新渲染之前被调用。这个钩子在实例创建后,每次数据变化导致虚拟 DOM 重新渲染和打补丁之前被调用。可以在这个钩子中进一步改变状态,这将不会触发额外的重渲染过程。
以下是 beforeUpdate
钩子的一些重要特点:
-
数据变化后、DOM 更新前:当 Vue 组件的数据变化后,
beforeUpdate
会在 DOM 更新之前被调用,使得你可以在 DOM 重新渲染之前执行一些操作。 -
不应修改数据:在
beforeUpdate
钩子中修改数据是不推荐的,因为这可能会导致无限循环的更新。如果需要根据当前的数据变化进行计算或修改数据,应该使用计算属性或侦听器。 -
场景应用:这个钩子适合用于在 DOM 重新渲染之前执行一些操作,例如读取旧的 DOM 状态之类的事情。
beforeUpdate
钩子通常用于以下场景:
-
获取更新前的 DOM 状态:有时可能需要在 DOM 重新渲染之前获取某些 DOM 元素的状态(如滚动位置、输入框内容等),此时可以在
beforeUpdate
中进行。 -
执行计算或类似操作:如果有基于当前数据变化的计算需要执行,并且这些计算不应该导致数据的再次变化,可以在这个钩子中进行。
下面是一个 beforeUpdate
钩子的示例:
new Vue({
el: '#app',
data: () => ({
message: '初始消息'
}),
beforeUpdate: function () {
console.log('beforeUpdate: 数据变化,但 DOM 还未重新渲染');
console.log('beforeUpdate: 旧的 message =', this.message);
},
updated: function () {
console.log('updated: DOM 已重新渲染');
console.log('updated: 新的 message =', this.message);
},
methods: {
updateMessage: function () {
this.message = '更新后的消息';
}
}
});
// 当调用 `updateMessage` 方法时,控制台将输出:
// "beforeUpdate: 数据变化,但 DOM 还未重新渲染"
// "beforeUpdate: 旧的 message = 初始消息"
// "updated: DOM 已重新渲染"
// "updated: 新的 message = 更新后的消息"
在这个示例中,当数据 message
发生变化时,beforeUpdate
钩子首先被调用,这时可以获取到旧的数据值和 DOM 状态。然后数据变化导致的 DOM 重新渲染发生,在 updated
钩子中可以看到新的数据和 DOM 状态。
需要注意的是,在 beforeUpdate
钩子中执行 DOM 操作通常是不安全的,因为这时 DOM 还没有更新以反映最新的虚拟 DOM 状态。如果你需要基于最新的数据状态执行 DOM 操作,应该使用 updated
钩子。
6.updated
总述:当数据更改导致的虚拟DOM重新渲染和打补丁之后调用。当这个钩子被调用时,组件DOM已经更新,所以现在可以执行依赖于DOM的操作。
updated
是 Vue 组件生命周期的一个重要钩子。它在组件的数据变化引起的虚拟 DOM 重新渲染和打补丁之后被调用。当此钩子被调用时,组件的 DOM 已经更新,因此可以执行依赖于 DOM 的操作。
以下是 updated
钩子的一些重要特点:
-
DOM 已更新:此时组件的 DOM 已经根据最新的数据被更新,可以执行依赖于最新 DOM 状态的操作。
-
避免在此钩子中修改数据:在
updated
钩子中修改数据是非常危险的,因为它可能会导致无限的更新循环。如果你需要根据 DOM 的更新状态来改变数据,应该考虑使用计算属性或侦听器。 -
可能会多次调用:每当组件的相关数据变化导致组件重新渲染时,
updated
钩子就会被调用。因此,确保你的代码可以处理这种重复执行的情况。 -
不保证所有子组件都被更新:当
updated
钩子被调用时,子组件可能还没有被更新。如果你想要确保所有的子组件也一同更新,可以等待this.$nextTick
之后再执行操作。
updated
钩子通常用于以下场景:
-
执行依赖于 DOM 的操作:如操纵滚动位置、聚焦输入框、使用第三方 DOM 库等。
-
执行依赖于最新数据的 DOM 操作:因为 DOM 已经更新,你可以安全地读取最新的 DOM 状态或值。
下面是一个 updated
钩子的示例:
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
methods: {
updateMessage() {
this.message = 'Updated message';
}
},
updated: function() {
console.log('The component is updated.');
// 可以执行依赖于 DOM 的操作,例如:
this.$nextTick(() => {
// 确保 DOM 完全更新
console.log('Actual DOM text content:', this.$el.textContent);
});
}
});
在这个示例中,当数据 message
改变,导致 Vue 重新渲染组件,updated
钩子会在 DOM 更新完成后被调用。使用 this.$nextTick
可以确保在 DOM 完全渲染后执行内部的回调函数。
this.$nextTick
是一个非常有用的实例方法,它用来延迟回调的执行直到下次 DOM 更新循环之后。在 updated
钩子中使用这个方法可以确保你的操作发生在 Vue 完成 DOM 更新之后,是处理 DOM 更新后逻辑的常见模式。
7.beforeDestroy
总述:在实例销毁之前调用。在这一步,实例仍然完全可用,这意味着可以在这个钩子中执行清理操作。
beforeDestroy
是 Vue 实例的生命周期钩子之一。这个钩子在 Vue 实例销毁前调用,此时实例仍然完全可用,这意味着所有的指令、子组件、事件监听器都处于活跃状态。beforeDestroy
钩子是做一些清理工作的好时机,比如取消定时器或者解除绑定事件,以避免内存泄露。
以下是 beforeDestroy
钩子的一些重要特点:
-
实例销毁前调用:当 Vue 实例即将销毁时,
beforeDestroy
钩子被调用。 -
清理工作:在这个生命周期钩子中,你应该执行必要的清理任务,比如取消未完成的 API 调用,移除自定义的事件监听器,取消 Vuex 状态的订阅等。
-
实例仍然完整:在
beforeDestroy
钩子被调用时,实例的所有指令、过滤器、子组件等都还是活跃的,因此你可以在此钩子中访问它们。 -
防止内存泄漏:组件销毁时没有清理(如事件监听器)可能会导致内存泄漏,因此
beforeDestroy
是最适合进行清理的时机。
beforeDestroy
钩子通常用于以下场景:
-
清除定时器:如果你在组件中使用了
setInterval
或setTimeout
,应该在beforeDestroy
钩子中清除。 -
解绑自定义事件监听器:如果你在组件的
mounted
钩子中添加了自定义事件监听器,应该在beforeDestroy
中解绑。 -
解除外部库的事件监听:如果你的组件使用了如 jQuery 或其他 JavaScript 库来绑定事件,也应该在这个钩子中解绑。
-
取消网络请求:如果你的组件发起了网络请求,为了防止它们在组件已经销毁后触发更新,你可以在
beforeDestroy
中取消这些请求。
下面是一个 beforeDestroy
钩子的示例:
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
beforeDestroy: function () {
console.log('beforeDestroy: 组件即将销毁,执行清理操作');
// 清除定时器
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
// 其他清理工作...
},
created: function() {
// 假设我们设置了一个定时器
this.timer = setInterval(() => {
console.log('Interval tick');
}, 1000);
}
});
在这个示例中,我们在 created
钩子中设置了一个定时器,这个定时器会每秒打印信息到控制台。为了防止在组件销毁后定时器仍然运行,我们在 beforeDestroy
钩子中清除了定时器。这样可以确保当组件销毁后,定时器不会继续触发,从而避免了可能的内存泄露和其他意外行为。
8.destroyed
总述:在实例销毁之后调用。调用这个钩子时,Vue实例中的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。
destroyed
是 Vue 实例的生命周期钩子之一。这个钩子在 Vue 实例被销毁后调用,此时组件的所有事务都已经被解绑,所有的子组件也都被销毁。destroyed
钩子常用于执行那些在组件销毁后需要进行的清理任务。
以下是 destroyed
钩子的一些重要特点:
-
组件已被销毁:当
destroyed
钩子被调用时,Vue 实例已经完成了销毁过程,包括解绑所有的指令、监听器和子组件。 -
执行后期清理工作:这是执行清理工作的最后机会,尽管大部分清理工作应该在
beforeDestroy
钩子中完成。 -
无法访问组件实例:由于组件已经被销毁,因此在
destroyed
钩子中无法访问组件的数据或方法。 -
适用于特定场景:这个钩子适用于那些需要在组件完全销毁后执行的任务,比如发送通知或清理全局对象。
destroyed
钩子通常用于以下场景:
-
清理全局事件或定时器:如果在应用的其他部分(如全局事件总线)设置了监听器,可能需要在
destroyed
钩子中进行清理。 -
发送销毁通知:如果需要通知其他系统部分或组件关于当前组件的销毁,可以在这个钩子中进行。
-
清理全局插件或库的实例:如果你在组件中使用了全局的插件或库,并且创建了特定的实例或连接,可能需要在销毁时进行清理。
下面是一个 destroyed
钩子的示例:
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
destroyed: function () {
console.log('destroyed: 组件已被销毁');
// 执行清理操作
// 例如,清理全局事件监听器或销毁全局插件实例
}
});
在这个示例中,destroyed
钩子被用来输出日志,表示组件已被销毁。这里可以加入任何必要的清理代码,以确保在组件销毁后不会留下任何副作用。需要注意的是,由于组件此时已经被销毁,因此在 destroyed
钩子中无法访问组件的任何响应式数据或方法。
9.activated
总述:这是keep-alive专属的钩子,它在组件被激活时调用。
activated
是 Vue 实例中与 keep-alive
组件配合使用的一个特殊生命周期钩子。当使用 keep-alive
对 Vue 组件进行缓存时,每当组件被激活(即重新插入到 DOM 中)时,activated
钩子就会被调用。这个钩子主要用于处理被 keep-alive
缓存的组件在激活时的逻辑。
以下是 activated
钩子的一些关键特点:
-
与
keep-alive
配合使用:activated
钩子仅在使用keep-alive
组件包裹的组件中有效。 -
组件重新激活时调用:当缓存的组件再次插入到 DOM 中时,
activated
钩子被调用。 -
适合执行激活逻辑:这个钩子适合用于执行组件被重新激活时的特定任务,如刷新数据或重置状态。
-
多次触发:与
created
或mounted
等只在组件实例创建时调用一次的生命周期钩子不同,activated
可以在组件每次激活时被多次调用。
activated
钩子通常用于以下场景:
-
更新数据:如果组件依赖外部数据源,可以在
activated
中重新获取最新数据,确保显示的内容是更新的。 -
重置状态:如果组件内部有一些状态,在组件隐藏后需要重置,那么可以在
activated
钩子中进行。 -
刷新界面:有时,组件在隐藏(deactivated)和重新显示(activated)时,可能需要根据新的条件更新界面。
下面是一个 activated
钩子的示例:
<template>
<keep-alive>
<my-component v-if="showMyComponent"></my-component>
</keep-alive>
</template>
<script>
export default {
data() {
return {
showMyComponent: true
};
},
components: {
MyComponent: {
template: '<div>我是一个组件</div>',
activated() {
console.log('activated: 组件被重新激活');
// 在这里执行特定的激活逻辑,比如数据更新
},
deactivated() {
console.log('deactivated: 组件不再展示');
}
}
}
};
</script>
在这个示例中,MyComponent
组件被 keep-alive
包裹。当 showMyComponent
的值改变导致组件显示或隐藏时,activated
和 deactivated
钩子将相应地被调用。这使得可以在组件每次变为活跃状态时执行特定的逻辑。
10.deactivated
总述:这也是keep-alive专属的钩子,它在组件被停用时调用。
deactivated
是 Vue.js 中的一个生命周期钩子,它与 activated
钩子一起工作,并且只在使用了 <keep-alive>
组件时才有意义。当一个被 <keep-alive>
缓存的组件被停用(即从 DOM 中移除)时,deactivated
钩子会被调用。
以下是 deactivated
生命周期钩子的详细解析:
-
配合
<keep-alive>
使用:deactivated
钩子仅在组件被<keep-alive>
包裹时才会被使用。如果组件没有被<keep-alive>
包裹,那么这个钩子就不会被调用。 -
组件停用时触发:当一个组件由于用户导航到不同的组件或条件渲染导致被隐藏时,如果该组件被
<keep-alive>
缓存,那么deactivated
钩子会被触发。 -
用于清理和释放资源:
deactivated
钩子是用来执行与停用相关的清理操作的理想之处,比如取消对外部事件或定时器的监听。 -
可能会多次调用:由于
<keep-alive>
允许组件在多次之间切换时保留状态,所以deactivated
可能在组件的生命周期内被调用多次,每次组件被停用时都会触发。 -
不会销毁组件:重要的是要理解,
deactivated
钩子的调用并不会销毁组件实例,组件所有的状态仍然会被保留。组件下次被激活时,activated
钩子会被调用,组件会以之前保留的状态呈现。
使用场景示例:
-
如果组件订阅了第三方库创建的全局事件,可能需要在
deactivated
钩子中取消订阅,防止内存泄漏。 -
如果组件启动了例如轮询的操作,可能需要在
deactivated
钩子中停止这些操作。 -
如果你想在组件每次被隐藏时重置其状态,可以在
deactivated
钩子中进行。
下面是一个 deactivated
钩子的代码示例:
<template>
<keep-alive>
<component-a v-if="isComponentAVisible"></component-a>
</keep-alive>
</template>
<script>
export default {
components: {
ComponentA: {
// ...
deactivated() {
// 当组件被停用时,这里的代码会被执行
console.log('Component A has been deactivated');
// 取消事件监听、停止定时器等
}
}
},
data() {
return {
isComponentAVisible: true,
};
},
methods: {
toggleComponentA() {
this.isComponentAVisible = !this.isComponentAVisible;
}
}
}
</script>
在这个例子中,每当 isComponentAVisible
变量改变,导致 component-a
被切换显示或隐藏时,ComponentA
的 deactivated
钩子会被触发。这允许我们进行任何必要的清理工作,以确保当组件不再显示时不会留下悬挂的事件监听器或未完成的任务。