Search K
Appearance
Appearance
📊 SEO元描述:2024年最新Vue生命周期钩子教程,详解created、mounted、updated、unmounted等钩子函数。包含完整生命周期示例,适合开发者掌握Vue组件生命周期管理。
核心关键词:Vue生命周期、Vue钩子函数、created、mounted、updated、unmounted、Vue组件生命周期
长尾关键词:Vue生命周期钩子怎么用、Vue组件生命周期详解、Vue钩子函数执行顺序、Vue.js生命周期管理
通过本节生命周期钩子,你将系统性掌握:
Vue生命周期是什么?这是理解Vue组件工作机制的核心问题。Vue生命周期是组件从创建到销毁的完整过程,包括初始化、挂载、更新、销毁等阶段,也是Vue组件管理的重要机制。
💡 设计理念:Vue生命周期钩子的设计目标是让开发者能够在组件的关键时刻执行特定逻辑,实现精确的控制和优化。
Vue 3生命周期钩子在组合式API中有了新的使用方式:
<template>
<div class="lifecycle-demo">
<h2>Vue生命周期钩子演示</h2>
<!-- 生命周期状态显示 -->
<div class="lifecycle-status">
<h3>当前生命周期状态</h3>
<div class="status-grid">
<div
v-for="(status, phase) in lifecycleStatus"
:key="phase"
class="status-item"
:class="{ active: status.active, completed: status.completed }"
>
<div class="status-icon">
{{ status.completed ? '✅' : (status.active ? '🔄' : '⏳') }}
</div>
<div class="status-info">
<h4>{{ status.name }}</h4>
<p>{{ status.description }}</p>
<small v-if="status.timestamp">{{ status.timestamp }}</small>
</div>
</div>
</div>
</div>
<!-- 生命周期日志 -->
<div class="lifecycle-log">
<h3>生命周期执行日志</h3>
<div class="log-controls">
<button @click="clearLog">清空日志</button>
<button @click="exportLog">导出日志</button>
<button @click="triggerUpdate">触发更新</button>
<button @click="forceRerender">强制重渲染</button>
</div>
<div class="log-container">
<div
v-for="(log, index) in lifecycleLogs"
:key="index"
class="log-entry"
:class="log.type"
>
<span class="log-time">{{ log.time }}</span>
<span class="log-phase">{{ log.phase }}</span>
<span class="log-message">{{ log.message }}</span>
<span v-if="log.data" class="log-data">{{ JSON.stringify(log.data) }}</span>
</div>
</div>
</div>
<!-- 子组件生命周期演示 -->
<div class="child-lifecycle">
<h3>子组件生命周期</h3>
<div class="child-controls">
<button @click="toggleChild">{{ showChild ? '销毁' : '创建' }}子组件</button>
<button @click="updateChildProps" :disabled="!showChild">更新子组件属性</button>
<button @click="recreateChild" :disabled="!showChild">重新创建子组件</button>
</div>
<ChildComponent
v-if="showChild"
:key="childKey"
:message="childMessage"
:count="childCount"
@child-lifecycle="handleChildLifecycle"
/>
</div>
<!-- 异步组件生命周期 -->
<div class="async-lifecycle">
<h3>异步组件生命周期</h3>
<div class="async-controls">
<button @click="loadAsyncComponent">加载异步组件</button>
<button @click="unloadAsyncComponent">卸载异步组件</button>
</div>
<Suspense v-if="showAsyncComponent">
<template #default>
<AsyncComponent @async-lifecycle="handleAsyncLifecycle" />
</template>
<template #fallback>
<div class="loading">加载中...</div>
</template>
</Suspense>
</div>
<!-- 生命周期性能监控 -->
<div class="performance-monitor">
<h3>生命周期性能监控</h3>
<div class="performance-stats">
<div class="stat-item">
<label>创建耗时:</label>
<span>{{ performanceStats.createTime }}ms</span>
</div>
<div class="stat-item">
<label>挂载耗时:</label>
<span>{{ performanceStats.mountTime }}ms</span>
</div>
<div class="stat-item">
<label>更新次数:</label>
<span>{{ performanceStats.updateCount }}</span>
</div>
<div class="stat-item">
<label>平均更新耗时:</label>
<span>{{ performanceStats.avgUpdateTime }}ms</span>
</div>
</div>
</div>
<!-- 数据变化触发更新 -->
<div class="update-triggers">
<h3>数据变化触发更新</h3>
<div class="trigger-controls">
<div class="control-group">
<label>计数器: {{ counter }}</label>
<button @click="counter++">增加</button>
<button @click="counter--">减少</button>
<button @click="counter = 0">重置</button>
</div>
<div class="control-group">
<label>用户信息:</label>
<input v-model="userInfo.name" placeholder="姓名">
<input v-model="userInfo.email" placeholder="邮箱">
<button @click="updateUserInfo">批量更新</button>
</div>
<div class="control-group">
<label>列表操作:</label>
<button @click="addItem">添加项目</button>
<button @click="removeItem">删除项目</button>
<button @click="shuffleItems">随机排序</button>
</div>
</div>
<div class="data-display">
<h4>当前数据状态</h4>
<pre>{{ JSON.stringify({ counter, userInfo, items }, null, 2) }}</pre>
</div>
</div>
</div>
</template>
<script>
import {
ref,
reactive,
computed,
watch,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
getCurrentInstance,
nextTick
} from 'vue'
// 子组件定义
const ChildComponent = {
name: 'ChildComponent',
props: ['message', 'count'],
emits: ['child-lifecycle'],
setup(props, { emit }) {
const instance = getCurrentInstance()
const childData = ref('子组件数据')
const renderCount = ref(0)
const logLifecycle = (phase, message, data = null) => {
const logEntry = {
phase,
message,
data,
time: new Date().toLocaleTimeString(),
component: 'ChildComponent'
}
console.log('子组件生命周期:', logEntry)
emit('child-lifecycle', logEntry)
}
// 组合式API生命周期钩子
onBeforeMount(() => {
logLifecycle('beforeMount', '子组件即将挂载')
})
onMounted(() => {
logLifecycle('mounted', '子组件已挂载', {
element: instance?.vnode.el?.tagName,
props: { ...props }
})
})
onBeforeUpdate(() => {
renderCount.value++
logLifecycle('beforeUpdate', '子组件即将更新', {
renderCount: renderCount.value,
newProps: { ...props }
})
})
onUpdated(() => {
logLifecycle('updated', '子组件已更新', {
renderCount: renderCount.value
})
})
onBeforeUnmount(() => {
logLifecycle('beforeUnmount', '子组件即将卸载')
})
onUnmounted(() => {
logLifecycle('unmounted', '子组件已卸载')
})
// 监听props变化
watch(() => props.message, (newVal, oldVal) => {
logLifecycle('watch', 'message属性变化', { newVal, oldVal })
})
watch(() => props.count, (newVal, oldVal) => {
logLifecycle('watch', 'count属性变化', { newVal, oldVal })
})
return {
childData,
renderCount
}
},
template: `
<div class="child-component">
<h4>子组件 (渲染次数: {{ renderCount }})</h4>
<p>接收消息: {{ message }}</p>
<p>接收计数: {{ count }}</p>
<p>内部数据: {{ childData }}</p>
<button @click="childData = '数据已更新: ' + Date.now()">更新内部数据</button>
</div>
`
}
// 异步组件定义
const AsyncComponent = {
name: 'AsyncComponent',
emits: ['async-lifecycle'],
async setup(props, { emit }) {
const logLifecycle = (phase, message) => {
emit('async-lifecycle', { phase, message, time: new Date().toLocaleTimeString() })
}
// 模拟异步数据加载
const asyncData = ref('加载中...')
onMounted(async () => {
logLifecycle('mounted', '异步组件已挂载')
// 模拟异步操作
await new Promise(resolve => setTimeout(resolve, 1000))
asyncData.value = '异步数据加载完成'
logLifecycle('dataLoaded', '异步数据加载完成')
})
onUnmounted(() => {
logLifecycle('unmounted', '异步组件已卸载')
})
return {
asyncData
}
},
template: `
<div class="async-component">
<h4>异步组件</h4>
<p>{{ asyncData }}</p>
</div>
`
}
export default {
name: 'LifecycleDemo',
components: {
ChildComponent,
AsyncComponent
},
setup() {
const instance = getCurrentInstance()
// 响应式数据
const lifecycleStatus = reactive({
beforeMount: { name: 'Before Mount', description: '挂载前', active: false, completed: false, timestamp: null },
mounted: { name: 'Mounted', description: '已挂载', active: false, completed: false, timestamp: null },
beforeUpdate: { name: 'Before Update', description: '更新前', active: false, completed: false, timestamp: null },
updated: { name: 'Updated', description: '已更新', active: false, completed: false, timestamp: null },
beforeUnmount: { name: 'Before Unmount', description: '卸载前', active: false, completed: false, timestamp: null },
unmounted: { name: 'Unmounted', description: '已卸载', active: false, completed: false, timestamp: null }
})
const lifecycleLogs = ref([])
const showChild = ref(false)
const childKey = ref(0)
const childMessage = ref('初始消息')
const childCount = ref(0)
const showAsyncComponent = ref(false)
const performanceStats = reactive({
createTime: 0,
mountTime: 0,
updateCount: 0,
updateTimes: [],
avgUpdateTime: 0
})
// 数据变化触发更新
const counter = ref(0)
const userInfo = reactive({
name: '张三',
email: 'zhangsan@example.com'
})
const items = ref(['项目1', '项目2', '项目3'])
// 性能监控
let createStartTime = performance.now()
let mountStartTime = 0
let updateStartTime = 0
// 日志记录函数
const addLog = (phase, message, type = 'info', data = null) => {
const logEntry = {
phase,
message,
type,
data,
time: new Date().toLocaleTimeString()
}
lifecycleLogs.value.unshift(logEntry)
// 限制日志数量
if (lifecycleLogs.value.length > 100) {
lifecycleLogs.value = lifecycleLogs.value.slice(0, 100)
}
}
// 更新生命周期状态
const updateLifecycleStatus = (phase, active = false, completed = false) => {
if (lifecycleStatus[phase]) {
lifecycleStatus[phase].active = active
lifecycleStatus[phase].completed = completed
lifecycleStatus[phase].timestamp = new Date().toLocaleTimeString()
}
}
// 生命周期钩子
onBeforeMount(() => {
mountStartTime = performance.now()
updateLifecycleStatus('beforeMount', true)
addLog('beforeMount', '组件即将挂载', 'lifecycle')
console.log('beforeMount: 组件即将挂载到DOM')
console.log('此时可以访问:', { data: true, computed: true, methods: true })
console.log('此时不能访问:', { $el: false, $refs: false })
})
onMounted(() => {
const mountTime = performance.now() - mountStartTime
performanceStats.createTime = performance.now() - createStartTime
performanceStats.mountTime = mountTime
updateLifecycleStatus('beforeMount', false, true)
updateLifecycleStatus('mounted', true)
addLog('mounted', `组件已挂载 (耗时: ${mountTime.toFixed(2)}ms)`, 'lifecycle')
console.log('mounted: 组件已挂载到DOM')
console.log('此时可以访问:', { $el: true, $refs: true, DOM: true })
console.log('根元素:', instance?.vnode.el)
// 模拟一些挂载后的操作
nextTick(() => {
updateLifecycleStatus('mounted', false, true)
addLog('mounted', 'DOM更新完成,可以进行DOM操作', 'success')
})
})
onBeforeUpdate(() => {
updateStartTime = performance.now()
updateLifecycleStatus('beforeUpdate', true)
addLog('beforeUpdate', '组件即将更新', 'lifecycle')
console.log('beforeUpdate: 组件即将重新渲染')
console.log('此时数据已更新,但DOM还未更新')
})
onUpdated(() => {
const updateTime = performance.now() - updateStartTime
performanceStats.updateCount++
performanceStats.updateTimes.push(updateTime)
performanceStats.avgUpdateTime = performanceStats.updateTimes.reduce((a, b) => a + b, 0) / performanceStats.updateTimes.length
updateLifecycleStatus('beforeUpdate', false, true)
updateLifecycleStatus('updated', true)
addLog('updated', `组件已更新 (耗时: ${updateTime.toFixed(2)}ms)`, 'lifecycle')
console.log('updated: 组件重新渲染完成')
console.log('此时数据和DOM都已更新')
nextTick(() => {
updateLifecycleStatus('updated', false, true)
})
})
onBeforeUnmount(() => {
updateLifecycleStatus('beforeUnmount', true)
addLog('beforeUnmount', '组件即将卸载', 'lifecycle')
console.log('beforeUnmount: 组件即将被卸载')
console.log('此时组件实例仍然可用,可以进行清理工作')
})
onUnmounted(() => {
updateLifecycleStatus('beforeUnmount', false, true)
updateLifecycleStatus('unmounted', true, true)
addLog('unmounted', '组件已卸载', 'lifecycle')
console.log('unmounted: 组件已被卸载')
console.log('此时应该清理定时器、事件监听器等')
})
// 方法
const clearLog = () => {
lifecycleLogs.value = []
}
const exportLog = () => {
const logData = JSON.stringify(lifecycleLogs.value, null, 2)
const blob = new Blob([logData], { type: 'application/json' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `lifecycle-log-${Date.now()}.json`
a.click()
URL.revokeObjectURL(url)
}
const triggerUpdate = () => {
// 触发多个数据更新
counter.value++
userInfo.name = `用户${Math.floor(Math.random() * 1000)}`
addLog('manual', '手动触发更新', 'action')
}
const forceRerender = () => {
// 强制重新渲染
instance?.proxy?.$forceUpdate?.()
addLog('manual', '强制重新渲染', 'action')
}
const toggleChild = () => {
showChild.value = !showChild.value
addLog('child', showChild.value ? '创建子组件' : '销毁子组件', 'action')
}
const updateChildProps = () => {
childMessage.value = `更新消息: ${new Date().toLocaleTimeString()}`
childCount.value++
addLog('child', '更新子组件属性', 'action')
}
const recreateChild = () => {
childKey.value++
addLog('child', '重新创建子组件', 'action')
}
const loadAsyncComponent = () => {
showAsyncComponent.value = true
addLog('async', '加载异步组件', 'action')
}
const unloadAsyncComponent = () => {
showAsyncComponent.value = false
addLog('async', '卸载异步组件', 'action')
}
const handleChildLifecycle = (logEntry) => {
addLog('child', `子组件: ${logEntry.message}`, 'child', logEntry.data)
}
const handleAsyncLifecycle = (logEntry) => {
addLog('async', `异步组件: ${logEntry.message}`, 'async')
}
const updateUserInfo = () => {
userInfo.name = `批量更新${Math.floor(Math.random() * 1000)}`
userInfo.email = `user${Math.floor(Math.random() * 1000)}@example.com`
addLog('data', '批量更新用户信息', 'action')
}
const addItem = () => {
items.value.push(`项目${items.value.length + 1}`)
addLog('data', '添加列表项目', 'action')
}
const removeItem = () => {
if (items.value.length > 0) {
items.value.pop()
addLog('data', '删除列表项目', 'action')
}
}
const shuffleItems = () => {
for (let i = items.value.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[items.value[i], items.value[j]] = [items.value[j], items.value[i]]
}
addLog('data', '随机排序列表', 'action')
}
return {
// 数据
lifecycleStatus,
lifecycleLogs,
showChild,
childKey,
childMessage,
childCount,
showAsyncComponent,
performanceStats,
counter,
userInfo,
items,
// 方法
clearLog,
exportLog,
triggerUpdate,
forceRerender,
toggleChild,
updateChildProps,
recreateChild,
loadAsyncComponent,
unloadAsyncComponent,
handleChildLifecycle,
handleAsyncLifecycle,
updateUserInfo,
addItem,
removeItem,
shuffleItems
}
}
}
</script>
<style scoped>
.lifecycle-demo {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.lifecycle-status,
.lifecycle-log,
.child-lifecycle,
.async-lifecycle,
.performance-monitor,
.update-triggers {
margin: 30px 0;
padding: 20px;
border: 1px solid #e0e0e0;
border-radius: 8px;
background-color: #fafafa;
}
.lifecycle-status h3,
.lifecycle-log h3,
.child-lifecycle h3,
.async-lifecycle h3,
.performance-monitor h3,
.update-triggers h3 {
margin-top: 0;
color: #42b983;
border-bottom: 2px solid #42b983;
padding-bottom: 10px;
}
.status-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 15px;
margin: 20px 0;
}
.status-item {
display: flex;
align-items: center;
padding: 15px;
background-color: white;
border-radius: 8px;
border: 1px solid #ddd;
transition: all 0.3s ease;
}
.status-item.active {
border-color: #ffc107;
background-color: #fff9c4;
}
.status-item.completed {
border-color: #28a745;
background-color: #d4edda;
}
.status-icon {
font-size: 24px;
margin-right: 15px;
}
.status-info h4 {
margin: 0 0 5px 0;
color: #333;
}
.status-info p {
margin: 0 0 5px 0;
color: #666;
font-size: 14px;
}
.status-info small {
color: #999;
font-size: 12px;
}
.log-controls {
display: flex;
gap: 10px;
margin-bottom: 15px;
flex-wrap: wrap;
}
.log-container {
max-height: 400px;
overflow-y: auto;
background-color: #1e1e1e;
border-radius: 4px;
padding: 15px;
font-family: 'Courier New', monospace;
}
.log-entry {
display: flex;
gap: 10px;
margin: 5px 0;
padding: 5px;
border-radius: 4px;
font-size: 12px;
}
.log-entry.lifecycle {
background-color: rgba(66, 185, 131, 0.1);
color: #42b983;
}
.log-entry.action {
background-color: rgba(255, 193, 7, 0.1);
color: #ffc107;
}
.log-entry.child {
background-color: rgba(255, 99, 132, 0.1);
color: #ff6384;
}
.log-entry.async {
background-color: rgba(54, 162, 235, 0.1);
color: #36a2eb;
}
.log-entry.success {
background-color: rgba(40, 167, 69, 0.1);
color: #28a745;
}
.log-time {
color: #999;
min-width: 80px;
}
.log-phase {
font-weight: bold;
min-width: 120px;
}
.log-message {
flex: 1;
}
.log-data {
color: #ccc;
font-style: italic;
}
.child-controls,
.async-controls {
display: flex;
gap: 10px;
margin-bottom: 15px;
flex-wrap: wrap;
}
.child-component {
background-color: #fff3e0;
padding: 15px;
border-radius: 8px;
border: 1px solid #ffcc02;
margin: 15px 0;
}
.async-component {
background-color: #e3f2fd;
padding: 15px;
border-radius: 8px;
border: 1px solid #2196f3;
margin: 15px 0;
}
.loading {
text-align: center;
padding: 20px;
color: #666;
font-style: italic;
}
.performance-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin: 20px 0;
}
.stat-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 15px;
background-color: white;
border-radius: 4px;
border: 1px solid #ddd;
}
.stat-item label {
font-weight: bold;
color: #333;
}
.stat-item span {
color: #42b983;
font-weight: bold;
}
.trigger-controls {
display: flex;
flex-direction: column;
gap: 15px;
margin: 20px 0;
}
.control-group {
display: flex;
align-items: center;
gap: 10px;
padding: 10px;
background-color: white;
border-radius: 4px;
border: 1px solid #ddd;
flex-wrap: wrap;
}
.control-group label {
font-weight: bold;
color: #333;
min-width: 80px;
}
.data-display {
background-color: white;
padding: 15px;
border-radius: 8px;
border: 1px solid #ddd;
margin-top: 15px;
}
.data-display h4 {
margin-top: 0;
color: #333;
}
.data-display pre {
background-color: #f8f9fa;
padding: 10px;
border-radius: 4px;
border: 1px solid #dee2e6;
font-size: 12px;
overflow-x: auto;
}
button {
padding: 8px 16px;
border: 1px solid #42b983;
background-color: #42b983;
color: white;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
button:hover {
background-color: #369870;
}
button:disabled {
background-color: #ccc;
border-color: #ccc;
cursor: not-allowed;
}
input {
padding: 6px 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
</style>| 选项式API | 组合式API | 执行时机 | 主要用途 |
|---|---|---|---|
| beforeCreate | setup() | 实例创建前 | 初始化配置 |
| created | setup() | 实例创建后 | 数据初始化 |
| beforeMount | onBeforeMount | 挂载前 | 挂载前准备 |
| mounted | onMounted | 挂载后 | DOM操作、API调用 |
| beforeUpdate | onBeforeUpdate | 更新前 | 更新前处理 |
| updated | onUpdated | 更新后 | DOM更新后操作 |
| beforeUnmount | onBeforeUnmount | 卸载前 | 清理工作 |
| unmounted | onUnmounted | 卸载后 | 资源释放 |
生命周期钩子的核心特点:
💼 最佳实践:在合适的生命周期钩子中执行相应的操作,避免在错误的时机进行DOM操作或数据处理。
export default {
setup() {
const data = ref(null)
const loading = ref(true)
const error = ref(null)
onMounted(async () => {
try {
loading.value = true
const response = await fetch('/api/data')
data.value = await response.json()
} catch (err) {
error.value = err.message
} finally {
loading.value = false
}
})
return { data, loading, error }
}
}export default {
setup() {
const handleResize = () => {
console.log('窗口大小改变')
}
const handleScroll = () => {
console.log('页面滚动')
}
onMounted(() => {
window.addEventListener('resize', handleResize)
window.addEventListener('scroll', handleScroll)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize)
window.removeEventListener('scroll', handleScroll)
})
}
}export default {
setup() {
const timer = ref(null)
const intervalId = ref(null)
onMounted(() => {
// 设置定时器
timer.value = setTimeout(() => {
console.log('延时任务执行')
}, 5000)
// 设置间隔器
intervalId.value = setInterval(() => {
console.log('定期任务执行')
}, 1000)
})
onBeforeUnmount(() => {
// 清理定时器
if (timer.value) {
clearTimeout(timer.value)
}
if (intervalId.value) {
clearInterval(intervalId.value)
}
})
}
}export default {
setup() {
const heavyComponent = ref(null)
const shouldLoadHeavyComponent = ref(false)
onMounted(() => {
// 延迟加载重型组件
setTimeout(() => {
shouldLoadHeavyComponent.value = true
}, 1000)
})
return {
heavyComponent,
shouldLoadHeavyComponent
}
}
}export default {
setup() {
const observers = []
const subscriptions = []
onMounted(() => {
// 创建观察器
const observer = new IntersectionObserver(() => {})
observers.push(observer)
// 创建订阅
const subscription = eventBus.subscribe('event', () => {})
subscriptions.push(subscription)
})
onBeforeUnmount(() => {
// 清理观察器
observers.forEach(observer => observer.disconnect())
// 清理订阅
subscriptions.forEach(sub => sub.unsubscribe())
})
}
}A: created时组件实例已创建但未挂载到DOM,可以访问数据但不能访问DOM。mounted时组件已挂载到DOM,可以进行DOM操作和API调用。
A: 在组件销毁前清理定时器、事件监听器等资源,防止内存泄漏。Vue 3中使用onBeforeUnmount钩子。
A: 可以,但要注意时机。在beforeUpdate中修改数据可能导致无限循环,在updated中修改数据会触发新的更新周期。
A: 通常在mounted钩子中执行异步操作,如API调用。如果需要在组件创建时就开始异步操作,可以在setup中执行。
A: 创建阶段:父beforeMount → 子beforeMount → 子mounted → 父mounted。销毁阶段:父beforeUnmount → 子beforeUnmount → 子unmounted → 父unmounted。
// 生命周期调试工具
const createLifecycleLogger = (componentName) => {
const log = (phase, ...args) => {
console.group(`[${componentName}] ${phase}`)
console.log('时间:', new Date().toISOString())
console.log('参数:', ...args)
console.groupEnd()
}
return {
onBeforeMount: () => log('beforeMount'),
onMounted: () => log('mounted'),
onBeforeUpdate: () => log('beforeUpdate'),
onUpdated: () => log('updated'),
onBeforeUnmount: () => log('beforeUnmount'),
onUnmounted: () => log('unmounted')
}
}// 生命周期性能监控
const createPerformanceMonitor = () => {
const timers = new Map()
return {
start(phase) {
timers.set(phase, performance.now())
},
end(phase) {
const startTime = timers.get(phase)
if (startTime) {
const duration = performance.now() - startTime
console.log(`${phase} 耗时: ${duration.toFixed(2)}ms`)
timers.delete(phase)
}
}
}
}"Vue生命周期钩子是组件开发的重要工具,让你能够在组件的关键时刻执行特定逻辑。通过掌握各个生命周期钩子的使用时机和最佳实践,你可以更好地管理组件状态、优化性能、防止内存泄漏。记住,合理使用生命周期钩子是编写高质量Vue组件的关键技能。下一步,我们将深入学习Vue的数据和方法!"