Vue 生命周期详解
Vue 组件的生命周期是理解 Vue 工作原理的核心概念之一。下面我将详细解释 Vue 的生命周期,并特别说明何时可以访问 data 数据。
完整的 Vue 生命周期图示
创建阶段:
beforeCreate → created → beforeMount → mounted更新阶段:
beforeUpdate → updated销毁阶段:
beforeDestroy → destroyed (Vue 2)
beforeUnmount → unmounted (Vue 3)生命周期钩子详解
1. beforeCreate
调用时机:实例初始化之后,数据观测和事件配置之前
特点:
无法访问到 data、computed、methods 等
组件实例的 data 和 methods 尚未初始化
2. created ✅ 可以首次访问 data
调用时机:实例创建完成后
特点:
可以访问 data、computed、methods 等
尚未挂载到 DOM,无法访问 $el
常用于异步数据请求、初始化数据
3. beforeMount
调用时机:挂载开始之前
特点:
可以访问 data,但模板尚未编译为 DOM
$el 尚不可用
4. mounted ✅ 可以访问 DOM 元素
调用时机:实例挂载到 DOM 后
特点:
可以访问到渲染后的 DOM 元素 ($el)
所有同步子组件已挂载
常用于 DOM 操作、第三方库初始化
5. beforeUpdate
调用时机:数据更新时,虚拟 DOM 重新渲染和打补丁之前
特点:
可以访问更新前的 DOM 状态
适合在更新前访问现有 DOM
6. updated
调用时机:数据更改导致的虚拟 DOM 重新渲染和打补丁之后
特点:
可以访问更新后的 DOM
避免在此钩子中更改状态,可能导致无限更新循环
7. beforeUnmount (Vue 3) / beforeDestroy (Vue 2)
调用时机:实例销毁之前
特点:
实例仍然完全可用
适合清理定时器、取消订阅等
8. unmounted (Vue 3) / destroyed (Vue 2)
调用时机:实例销毁后
特点:
所有指令已解绑,事件监听器已移除
所有子实例也已销毁
实际示例演示
下面是一个完整的示例,展示各个生命周期阶段的执行顺序和 data 的可访问性:
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue 生命周期详解</title><script src="https://unpkg.com/vue@3/dist/vue.global.js"></script><style>body {font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;line-height: 1.6;color: #333;max-width: 1000px;margin: 0 auto;padding: 20px;background-color: #f5f7fa;}.container {display: flex;gap: 20px;margin-top: 20px;}.lifecycle-explanation {flex: 1;background: white;padding: 20px;border-radius: 8px;box-shadow: 0 2px 10px rgba(0,0,0,0.1);}.demo-component {flex: 1;background: white;padding: 20px;border-radius: 8px;box-shadow: 0 2px 10px rgba(0,0,0,0.1);}h1 {color: #2c3e50;border-bottom: 2px solid #42b883;padding-bottom: 10px;}h2 {color: #42b883;}.phase {margin: 15px 0;padding: 10px;border-left: 4px solid #42b883;background-color: #f8f9fa;}.phase h3 {margin-top: 0;color: #2c3e50;}.log-container {background: #2c3e50;color: #42b883;padding: 15px;border-radius: 5px;height: 300px;overflow-y: auto;font-family: 'Courier New', monospace;margin-top: 15px;}button {background: #42b883;color: white;border: none;padding: 8px 15px;border-radius: 4px;cursor: pointer;margin: 5px;}button:hover {background: #3aa876;}.data-access {background: #e8f5e9;padding: 10px;border-radius: 4px;margin: 10px 0;}.highlight {background-color: #fff3cd;padding: 10px;border-radius: 4px;border-left: 4px solid #ffc107;}</style>
</head>
<body><div id="app"><h1>Vue 生命周期详解</h1><div class="container"><div class="lifecycle-explanation"><h2>生命周期阶段</h2><div class="phase"><h3>创建阶段</h3><p><strong>beforeCreate</strong> - 实例初始化后,数据观测和事件配置之前</p><p><strong>created</strong> - <span class="highlight">可以首次访问 data</span>,但尚未挂载到 DOM</p><p><strong>beforeMount</strong> - 挂载开始之前,模板编译完成</p><p><strong>mounted</strong> - 实例已挂载到 DOM,<span class="highlight">可以访问 DOM 元素</span></p></div><div class="phase"><h3>更新阶段</h3><p><strong>beforeUpdate</strong> - 数据更新时,DOM 重新渲染前</p><p><strong>updated</strong> - 数据更新后,DOM 已重新渲染</p></div><div class="phase"><h3>卸载阶段</h3><p><strong>beforeUnmount</strong> - 实例销毁之前</p><p><strong>unmounted</strong> - 实例销毁后</p></div><div class="data-access"><h3>数据访问时机</h3><p><strong>✅ created 及之后</strong> - 可以访问 data、computed、methods</p><p><strong>✅ mounted 及之后</strong> - 可以访问 DOM 元素</p><p><strong>❌ beforeCreate</strong> - 无法访问 data</p></div></div><div class="demo-component"><h2>生命周期演示</h2><p>计数器: {{ count }}</p><button @click="increment">增加计数</button><button @click="reset">重置</button><button @click="toggleComponent" v-if="showComponent">卸载组件</button><button @click="toggleComponent" v-else>加载组件</button><div class="log-container"><div v-for="log in logs" :key="log.id">{{ log.message }}</div></div></div></div></div><script>const { createApp } = Vue;// 子组件定义const LifecycleDemo = {name: 'LifecycleDemo',template: `<div style="border: 1px solid #42b883; padding: 10px; margin: 10px 0;"><h3>子组件</h3><p>子组件计数: {{ childCount }}</p><button @click="childCount++">子组件计数+1</button></div>`,data() {return {childCount: 0}},beforeCreate() {this.$parent.logLifecycle('子组件 - beforeCreate', 'childCount: ' + (typeof this.childCount));},created() {this.$parent.logLifecycle('子组件 - created', 'childCount: ' + this.childCount);},beforeMount() {this.$parent.logLifecycle('子组件 - beforeMount');},mounted() {this.$parent.logLifecycle('子组件 - mounted');},beforeUpdate() {this.$parent.logLifecycle('子组件 - beforeUpdate', 'childCount: ' + this.childCount);},updated() {this.$parent.logLifecycle('子组件 - updated');},beforeUnmount() {this.$parent.logLifecycle('子组件 - beforeUnmount');},unmounted() {this.$parent.logLifecycle('子组件 - unmounted');}};// 主应用const app = createApp({data() {return {count: 0,logs: [],logId: 0,showComponent: true}},components: {LifecycleDemo},methods: {logLifecycle(hook, extra = '') {const message = `[${new Date().toLocaleTimeString()}] ${hook} ${extra}`;this.logs.push({ id: this.logId++, message });// 保持日志区域滚动到底部this.$nextTick(() => {const logContainer = this.$el.querySelector('.log-container');if (logContainer) {logContainer.scrollTop = logContainer.scrollHeight;}});},increment() {this.count++;},reset() {this.count = 0;this.logs = [];this.logId = 0;},toggleComponent() {this.showComponent = !this.showComponent;}},beforeCreate() {// 此时无法访问 datathis.logLifecycle('父组件 - beforeCreate', `count: ${typeof this.count} (此时无法访问data)`);},created() {// 此时可以访问 datathis.logLifecycle('父组件 - created', `count: ${this.count} (此时可以访问data)`);},beforeMount() {this.logLifecycle('父组件 - beforeMount');},mounted() {this.logLifecycle('父组件 - mounted');},beforeUpdate() {this.logLifecycle('父组件 - beforeUpdate', `count: ${this.count}`);},updated() {this.logLifecycle('父组件 - updated');},beforeUnmount() {this.logLifecycle('父组件 - beforeUnmount');},unmounted() {this.logLifecycle('父组件 - unmounted');}});app.mount('#app');</script>
</body>
</html>关键要点总结
created 阶段:首次可以访问 data、computed、methods 等响应式数据
mounted 阶段:首次可以访问 DOM 元素,适合进行 DOM 操作
更新阶段:数据变化时触发,用于响应数据变化
卸载阶段:用于清理工作,如取消事件监听、清除定时器等
这个示例直观地展示了 Vue 生命周期的各个阶段,特别是清晰地标明了何时可以访问 data 数据。你可以通过操作界面上的按钮来触发不同生命周期阶段,观察控制台输出的日志信息。
