Skip to content

组件生命周期

组件生命周期是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. 首次渲染

  1. onBeforeMount
  2. onMounted

2. 数据更新

  1. onBeforeUpdate
  2. onUpdated

3. 组件卸载

  1. onBeforeUnmount
  2. 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等内容。

© 2026 编程马·菜鸟教程 版权所有