Appearance
组件生命周期
组件生命周期是Vue3中的一个重要概念,它描述了组件从创建到销毁的整个过程。本章节将详细介绍Vue3中的组件生命周期钩子,以及它们的使用方法和最佳实践。
什么是组件生命周期?
组件生命周期是指组件从创建、挂载、更新到销毁的整个过程。在这个过程中,Vue3会触发一系列的生命周期钩子函数,你可以在这些钩子函数中执行相应的操作。
Vue3的生命周期钩子
Vue3的组合式API提供了以下生命周期钩子:
1. 挂载阶段
- onBeforeMount:组件挂载前执行
- onMounted:组件挂载后执行
2. 更新阶段
- onBeforeUpdate:组件更新前执行
- onUpdated:组件更新后执行
3. 卸载阶段
- onBeforeUnmount:组件卸载前执行
- onUnmounted:组件卸载后执行
4. 其他生命周期钩子
- onErrorCaptured:捕获组件树中的错误
- onRenderTracked:跟踪组件渲染时的依赖
- onRenderTriggered:触发组件渲染的依赖
- onActivated:组件被激活时执行(用于keep-alive组件)
- onDeactivated:组件被停用时执行(用于keep-alive组件)
生命周期钩子的使用
1. 基本使用
vue
<template>
<div class="component">
<h1>{{ title }}</h1>
<button @click="count++">Increment</button>
<p>Count: {{ count }}</p>
</div>
</template>
<script setup>
import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from 'vue'
const title = ref('Hello Vue3!')
const count = ref(0)
onBeforeMount(() => {
console.log('Component before mount')
})
onMounted(() => {
console.log('Component mounted')
})
onBeforeUpdate(() => {
console.log('Component before update')
})
onUpdated(() => {
console.log('Component updated')
})
onBeforeUnmount(() => {
console.log('Component before unmount')
})
onUnmounted(() => {
console.log('Component unmounted')
})
</script>2. 实际应用场景
onMounted:初始化操作
vue
<template>
<div class="component">
<h1>User List</h1>
<ul>
<li v-for="user in users" :key="user.id">
{{ user.name }}
</li>
</ul>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const users = ref([])
onMounted(async () => {
// 组件挂载后获取数据
try {
const response = await fetch('https://api.example.com/users')
const data = await response.json()
users.value = data
} catch (error) {
console.error('Error fetching users:', error)
}
})
</script>onUnmounted:清理操作
vue
<template>
<div class="component">
<h1>Timer</h1>
<p>Count: {{ count }}</p>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const count = ref(0)
let timer = null
onMounted(() => {
// 组件挂载后启动定时器
timer = setInterval(() => {
count.value++
}, 1000)
})
onUnmounted(() => {
// 组件卸载前清理定时器
if (timer) {
clearInterval(timer)
}
})
</script>onBeforeUpdate:更新前准备
vue
<template>
<div class="component">
<h1>Resize Observer</h1>
<div ref="box" class="box" :style="{ width: `${width}px`, height: `${height}px` }"></div>
<button @click="width += 50; height += 50">Increase Size</button>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUpdate } from 'vue'
const box = ref(null)
const width = ref(100)
const height = ref(100)
onMounted(() => {
console.log('Box size:', box.value.offsetWidth, 'x', box.value.offsetHeight)
})
onBeforeUpdate(() => {
console.log('Before update - Box size:', box.value.offsetWidth, 'x', box.value.offsetHeight)
})
</script>
<style scoped>
.box {
background-color: #42b983;
margin: 20px 0;
}
</style>生命周期钩子的执行顺序
1. 首次渲染
- onBeforeMount
- onMounted
2. 数据更新
- onBeforeUpdate
- onUpdated
3. 组件卸载
- onBeforeUnmount
- onUnmounted
生命周期钩子的最佳实践
1. 合理使用生命周期钩子
- onMounted:用于初始化操作,如获取数据、启动定时器、添加事件监听器等
- onUnmounted:用于清理操作,如清除定时器、移除事件监听器等
- onBeforeUpdate:用于在组件更新前执行一些准备工作
- onUpdated:用于在组件更新后执行一些操作,如获取更新后的DOM元素尺寸
2. 避免在生命周期钩子中执行昂贵的操作
- 避免在onMounted中执行耗时的操作,以免阻塞组件的挂载
- 避免在onUpdated中执行会触发再次更新的操作,以免导致无限循环
3. 使用组合式API的优势
在Vue3的组合式API中,你可以根据功能组织代码,将相关的逻辑放在一起:
vue
<template>
<div class="component">
<h1>User List</h1>
<ul>
<li v-for="user in users" :key="user.id">
{{ user.name }}
</li>
</ul>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
// 用户数据相关逻辑
const users = ref([])
let usersTimer = null
const fetchUsers = async () => {
try {
const response = await fetch('https://api.example.com/users')
const data = await response.json()
users.value = data
} catch (error) {
console.error('Error fetching users:', error)
}
}
// 生命周期钩子
onMounted(() => {
fetchUsers()
// 每5分钟刷新一次数据
usersTimer = setInterval(fetchUsers, 5 * 60 * 1000)
})
onUnmounted(() => {
if (usersTimer) {
clearInterval(usersTimer)
}
})
</script>生命周期钩子的使用场景
1. 数据获取
vue
<template>
<div class="component">
<h1>Posts</h1>
<div v-if="loading">Loading...</div>
<div v-else-if="error">{{ error }}</div>
<ul v-else>
<li v-for="post in posts" :key="post.id">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</li>
</ul>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const posts = ref([])
const loading = ref(true)
const error = ref('')
onMounted(async () => {
try {
const response = await fetch('https://api.example.com/posts')
if (!response.ok) {
throw new Error('Failed to fetch posts')
}
const data = await response.json()
posts.value = data
} catch (err) {
error.value = err.message
} finally {
loading.value = false
}
})
</script>2. 事件监听
vue
<template>
<div class="component">
<h1>Mouse Position</h1>
<p>X: {{ mouseX }}, Y: {{ mouseY }}</p>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const mouseX = ref(0)
const mouseY = ref(0)
const handleMouseMove = (event) => {
mouseX.value = event.clientX
mouseY.value = event.clientY
}
onMounted(() => {
window.addEventListener('mousemove', handleMouseMove)
})
onUnmounted(() => {
window.removeEventListener('mousemove', handleMouseMove)
})
</script>3. 第三方库初始化
vue
<template>
<div class="component">
<h1>Chart</h1>
<div ref="chartContainer" class="chart-container"></div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import Chart from 'chart.js'
const chartContainer = ref(null)
let chart = null
onMounted(() => {
// 初始化图表
const ctx = chartContainer.value.getContext('2d')
chart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
})
})
onUnmounted(() => {
// 销毁图表
if (chart) {
chart.destroy()
}
})
</script>
<style scoped>
.chart-container {
width: 400px;
height: 300px;
}
</style>总结
组件生命周期是Vue3中的一个重要概念,它描述了组件从创建到销毁的整个过程。通过生命周期钩子,你可以在组件的不同阶段执行相应的操作,如初始化数据、添加事件监听器、清理资源等。
在使用生命周期钩子时,你应该合理选择钩子函数,避免执行昂贵的操作,以及利用组合式API的优势组织代码。
在后续的章节中,我们将学习Vue3的组合式API,包括setup语法糖、响应式API等内容。
