自在学
分类课程AI导师价格
分类课程AI导师价格
插槽
11 / 15
组合式API
自在学

© 2025 - 2026 自在学,保留所有权利。

公网安备湘公网安备43020302000292号 | 湘ICP备2025148919号-1

关于我们隐私政策使用条款

© 2025 自在学,保留所有权利。

公网安备湘公网安备43020302000292号湘ICP备2025148919号-1

编程Vue指南生命周期

生命周期

每个Vue组件都会经历从创建到销毁的完整生命周期。在这个过程中,Vue会在特定的时机调用一些函数,这些函数就是生命周期钩子。通过生命周期钩子,我们可以在组件的不同阶段执行操作,比如初始化数据、发送请求、清理资源等。

理解生命周期对于开发Vue应用非常重要。它帮助我们理解组件的工作机制,知道在什么时候可以访问DOM,什么时候可以发送请求,什么时候需要清理资源。在这一堂课中,我们将深入学习Vue的生命周期。

生命周期


什么是生命周期

Vue组件的生命周期可以分为几个阶段:创建、挂载、更新和销毁。每个阶段都有对应的钩子函数,我们可以在这些钩子中执行特定的操作。

让我们通过一个简单的例子来理解生命周期:

<div id="app"> <lifecycle-demo :count="count"></lifecycle-demo> <button @click="count++">增加计数</button> </div> <script> const { createApp, ref } = Vue; const LifecycleDemo = { props: ['count'], beforeCreate() { console.log('beforeCreate: 组件实例刚被创建,数据和方法还未初始化'); }, created() { console.log('created: 组件实例创建完成,数据和方法已初始化,但还未挂载到DOM'); }, beforeMount() { console.log('beforeMount: 组件挂载到DOM之前'); }, mounted() { console.log('mounted: 组件已挂载到DOM,可以访问DOM元素'); }, beforeUpdate() { console.log('beforeUpdate: 组件更新之前'); }, updated() { console.log('updated: 组件更新完成'); }, beforeUnmount() { console.log('beforeUnmount: 组件卸载之前'); }, unmounted() { console.log('unmounted: 组件已卸载'); }, template: ` <div> <p>计数:{{ count }}</p> </div> ` }; const app = createApp({ setup() { const count = ref(0); return { count }; }, components: { 'lifecycle-demo': LifecycleDemo } }); app.mount('#app'); </script>

如果你运行这段代码并观察控制台,你会看到各个生命周期钩子的执行顺序。这帮助我们理解组件在不同阶段的状态。


选项式API的生命周期钩子

在选项式API(Options API)中,我们可以通过在组件对象的选项中直接声明各类生命周期钩子函数(如 beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeUnmount、unmounted 等)。 这些钩子会在组件的不同生命周期阶段自动依次调用,允许我们在组件初始化、DOM 挂载、数据变更、卸载等关键时刻插入自定义逻辑。例如,你可以在 created 钩子里发起数据请求、在 mounted 钩子中操作 DOM、在 beforeUnmount 中做清理工作。 每个生命周期钩子都作为组件对象的一个方法选项直接存在,与 data、methods、computed 等属性并列。这样可以帮助我们精确掌控组件的整个生命周期过程。

<div id="app"> <component-a></component-a> </div> <script> const { createApp } = Vue; const ComponentA = { data() { return { message: 'Hello Vue' }; }, beforeCreate() { // 此时this还未创建,无法访问data、methods等 console.log('beforeCreate'); }, created() { // 此时可以访问data、methods等,但DOM还未创建 console.log('created', this.message); // 可以在这里发送请求、初始化数据等 }, beforeMount() { // DOM还未挂载 console.log('beforeMount'); }, mounted() { // DOM已挂载,可以访问DOM元素 console.log('mounted'); // 可以在这里操作DOM、初始化第三方库等 }, template: ` <div> <p>{{ message }}</p> </div> ` }; const app = createApp({}); app.component('component-a', ComponentA); app.mount('#app'); </script>
  • beforeCreate:组件实例刚被创建,此时this还未创建,无法访问data、methods`等。这个钩子很少使用。
  • created:组件实例创建完成,此时可以访问data、methods`等,但DOM还未创建。这是发送请求、初始化数据的好时机。
  • beforeMount`:组件挂载到DOM之前,此时模板已经编译完成,但还未挂载到页面。
  • mounted`:组件已挂载到DOM,此时可以访问DOM元素。这是操作DOM、初始化第三方库的好时机。

更新阶段的钩子

当组件的数据(如 data、props 等)发生变化时,Vue 会自动触发一组“更新阶段的生命周期钩子”。这些钩子的执行顺序如下:

  1. beforeUpdate:在响应式数据发生变化,组件即将重新渲染前调用。此时数据已是最新的,但页面上的 DOM 尚未被更新为新状态。你可以在这里访问 this 获取更新后的数据,但千万不要在这里再次修改数据,否则可能导致无限重渲。
  2. updated:在组件的 DOM 已经根据最新的数据完成了渲染后调用。这个钩子可以安全地访问已更新的 DOM 元素,通常用于依赖 DOM 结构的第三方库初始化或其他操作。不过,请避免在此处再修改数据,否则会进入死循环。

通过这些钩子,你可以在数据变更、组件重新渲染的各个阶段进行相应的操作,比如:在 DOM 更新前执行某些计算逻辑,在 DOM 更新后与界面进行交互等。

<div id="app"> <counter-component></counter-component> </div> <script> const { createApp } = Vue; const CounterComponent = { data() { return { count: 0 }; }, beforeUpdate() { // 数据已更新,但DOM还未更新 console.log('beforeUpdate', this.count); }, updated() { // DOM已更新 console.log('updated', this.count); // 可以在这里操作更新后的DOM }, methods: { increment() { this.count++; } }, template: ` <div> <p>计数:{{ count }}</p> <button @click="increment">增加</button> </div> ` }; const app = createApp({}); app.component('counter-component', CounterComponent); app.mount('#app'); </script>
  • beforeUpdate:数据已更新,但DOM还未更新。这个钩子很少使用。
  • updated:DOM已更新。可以在这里操作更新后的DOM,但要注意避免在这里修改数据,否则可能导致无限循环。

销毁阶段的钩子

当组件被销毁(卸载)时,会依次触发两个销毁阶段(卸载阶段)的生命周期钩子:beforeUnmount 和 unmounted。

  • beforeUnmount:组件实例将要被卸载时调用,在这个钩子中通常进行一些清理操作,比如清除定时器、移除事件监听等。此时组件仍然可以访问所有的数据和 DOM。
  • unmounted:组件实例已经被卸载并销毁时调用,这时你已经无法访问组件实例中的数据和 DOM 节点,常用于一些最终的清理操作或者发送日志等。

这些钩子主要用于组件销毁时的资源管理,避免内存泄漏或副作用残留。

<div id="app"> <button @click="show = !show">切换显示</button> <component-b v-if="show"></component-b> </div> <script> const { createApp, ref } = Vue; const ComponentB = { data() { return { timer: null }; }, mounted() { // 创建一个定时器 this.timer = setInterval(() => { console.log('定时器运行中'); }, 1000); }, beforeUnmount() { // 组件卸载之前,清理资源 console.log('beforeUnmount'); if (this.timer) { clearInterval(this.timer); } }, unmounted() { // 组件已卸载 console.log('unmounted'); }, template: ` <div> <p>这是组件B</p> </div> ` }; const app = createApp({ setup() { const show = ref(true); return { show }; }, components: { 'component-b': ComponentB } }); app.mount('#app'); </script>
  • beforeUnmount`:组件卸载之前,这是清理资源的好时机,比如清除定时器、取消请求、移除事件监听器等。
  • unmounted`:组件已卸载。这个钩子很少使用。

在组件销毁时,一定要清理资源,比如定时器、事件监听器等。否则可能导致内存泄漏。


组合式API的生命周期钩子

在组合式 API 中,生命周期钩子不能像选项式 API 那样直接写作对象方法,而是需要单独从 Vue 中按需导入,然后在 setup 函数内调用对应的钩子函数。例如:

import { onMounted, onUnmounted } from 'vue'; setup() { onMounted(() => { // 组件挂载后执行的逻辑 }); onUnmounted(() => { // 组件卸载时执行的逻辑 }); }

常用的生命周期钩子包括 onBeforeMount、onMounted、onBeforeUpdate、onUpdated、onBeforeUnmount、onUnmounted 等,全部以“on”为前缀,便于区分。

<div id="app"> <component-c></component-c> </div> <script> const { createApp, ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } = Vue; const ComponentC = { setup() { const count = ref(0); onBeforeMount(() => { console.log('onBeforeMount'); }); onMounted(() => { console.log('onMounted'); // 可以在这里操作DOM、初始化第三方库等 }); onBeforeUpdate(() => { console.log('onBeforeUpdate', count.value); }); onUpdated(() => { console.log('onUpdated', count.value); }); onBeforeUnmount(() => { console.log('onBeforeUnmount'); // 清理资源 }); onUnmounted(() => { console.log('onUnmounted'); }); const increment = () => { count.value++; }; return { count, increment }; }, template: ` <div> <p>计数:{{ count }}</p> <button @click="increment">增加</button> </div> ` }; const app = createApp({}); app.component('component-c', ComponentC); app.mount('#app'); </script>

在组合式API中,生命周期钩子的命名稍有不同:beforeCreate和created被setup替代,其他钩子都加上了on前缀。

注意,组合式API中没有beforeCreate和created钩子,因为setup函数在这些钩子之前执行。如果你需要在组件创建时执行操作,直接在setup中执行即可。


生命周期钩子的使用场景

不同的生命周期钩子适用于不同的场景。让我们看一些实际的使用场景:

在created/mounted中发送请求

<div id="app"> <user-list></user-list> </div> <script> const { createApp, ref } = Vue; const UserList = { data() { return { users: [], loading: false }; }, async created() { // 在created中发送请求,可以更早获取数据 this.loading = true; try { // 模拟API请求 await new Promise(resolve => setTimeout(resolve, 1000)); this.users = [ { id: 1, name: '张三', age: 25 }, { id: 2, name: '李四', age: 30 } ]; } finally { this.loading = false; } }, template: ` <div> <div v-if="loading">加载中...</div> <ul v-else> <li v-for="user in users" :key="user.id"> {{ user.name }},{{ user.age }}岁 </li> </ul> </div> ` }; const app = createApp({}); app.component('user-list', UserList); app.mount('#app'); </script>

在这个例子中,我们在created钩子中发送请求获取用户列表。虽然也可以在mounted中发送请求,但在created中发送可以更早获取数据。

在mounted中操作DOM

<div id="app"> <chart-component></chart-component> </div> <script> const { createApp } = Vue; const ChartComponent = { mounted() { // DOM已挂载,可以初始化图表库 const canvas = this.$el.querySelector('canvas'); if (canvas) { const ctx = canvas.getContext('2d'); // 绘制图表 ctx.fillStyle = '#42b983'; ctx.fillRect(10, 10, 100, 50); } }, template: ` <div> <canvas width="200" height="100"></canvas> </div> ` }; const app = createApp({}); app.component('chart-component', ChartComponent); app.mount('#app'); </script>

在这个例子中,我们在mounted钩子中操作DOM,初始化图表。因为只有在mounted之后,DOM元素才真正存在。

在beforeUnmount中清理资源

<div id="app"> <button @click="show = !show">切换显示</button> <timer-component v-if="show"></timer-component> </div> <script> const { createApp, ref } = Vue; const TimerComponent = { data() { return { count: 0, timer: null }; }, mounted() { // 创建定时器 this.timer = setInterval(() => { this.count++; }, 1000); }, beforeUnmount() { // 清理定时器 if (this.timer) { clearInterval(this.timer); this.timer = null; } }, template: ` <div> <p>计时:{{ count }}秒</p> </div> ` }; const app = createApp({ setup() { const show = ref(true); return { show }; }, components: { 'timer-component': TimerComponent } }); app.mount('#app'); </script>

在这个例子中,我们在beforeUnmount钩子中清理定时器。如果不清理,定时器会继续运行,导致内存泄漏。

生命周期图示

让我们通过一个图示来理解完整的生命周期流程:


综合示例

下面我们将通过一个更详细的综合示例,来全面巩固和理解 Vue 组件的生命周期。
在这个示例中,我们会自定义一个组件,并在每个生命周期钩子中进行不同的操作与日志记录,以观察生命周期的完整流程,以及每一步执行的时机和作用。 你可以通过切换、修改 props 等操作,直观地看到各生命周期钩子的调用顺序和效果。

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>生命周期钩子示例</title> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <style> body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; } button { padding: 8px 16px; margin-right: 10px; margin-bottom: 10px; background-color: #42b983; color: white; border: none; border-radius: 4px; cursor: pointer; } .logs { margin-top: 20px; padding: 15px; background-color: #f5f5f5; border-radius: 4px; } ul { list-style: none; padding: 0; } li { padding: 5px 0; border-bottom: 1px solid #ddd; } </style> </head> <body> <div id="app"> <button @click="show = !show">切换显示</button> <lifecycle-example v-if="show" :message="message"></lifecycle-example> <button @click="message = '新消息'">改变消息</button> </div> <script> const { createApp, ref } = Vue; const LifecycleExample = { props: ['message'], data() { return { logs: [] }; }, beforeCreate() { this.logs = []; this.addLog('beforeCreate: 组件实例刚被创建'); }, created() { this.addLog('created: 组件实例创建完成'); }, beforeMount() { this.addLog('beforeMount: 组件挂载之前'); }, mounted() { this.addLog('mounted: 组件已挂载'); }, beforeUpdate() { this.addLog('beforeUpdate: 组件更新之前'); }, updated() { this.addLog('updated: 组件更新完成'); }, beforeUnmount() { this.addLog('beforeUnmount: 组件卸载之前'); }, unmounted() { this.addLog('unmounted: 组件已卸载'); }, methods: { addLog(message) { const time = new Date().toLocaleTimeString(); this.logs.push(`[${time}] ${message}`); } }, template: ` <div> <h3>生命周期示例</h3> <p>消息:{{ message }}</p> <div class="logs"> <h4>生命周期日志:</h4> <ul> <li v-for="(log, index) in logs" :key="index">{{ log }}</li> </ul> </div> </div> ` }; const app = createApp({ setup() { const show = ref(true); const message = ref('初始消息'); return { show, message }; }, components: { 'lifecycle-example': LifecycleExample } }); app.mount('#app'); </script> </body> </html>

在这个例子中,我们创建了一个组件,它会在各个生命周期钩子中记录日志。通过观察日志,我们可以清楚地看到组件生命周期的执行顺序。


下一步

在这一部分中,我们学习了Vue的生命周期钩子。我们了解了组件从创建到销毁的完整生命周期,学习了选项式API和组合式API中的生命周期钩子,以及它们的使用场景。 理解生命周期对于开发Vue应用非常重要。它帮助我们理解组件的工作机制,知道在什么时候可以访问DOM,什么时候可以发送请求,什么时候需要清理资源。

在下一堂课,我们将学习组合式API,了解setup函数、组合式函数等高级特性。

  • 什么是生命周期
  • 选项式API的生命周期钩子
  • 更新阶段的钩子
  • 销毁阶段的钩子
  • 组合式API的生命周期钩子
  • 生命周期钩子的使用场景
    • 在created/mounted中发送请求
    • 在mounted中操作DOM
    • 在beforeUnmount中清理资源
  • 生命周期图示
  • 综合示例
  • 下一步

目录

  • 什么是生命周期
  • 选项式API的生命周期钩子
  • 更新阶段的钩子
  • 销毁阶段的钩子
  • 组合式API的生命周期钩子
  • 生命周期钩子的使用场景
    • 在created/mounted中发送请求
    • 在mounted中操作DOM
    • 在beforeUnmount中清理资源
  • 生命周期图示
  • 综合示例
  • 下一步