生命周期与数据请求
博客详情页要显示文章内容,就必须在组件"上场"时去请求接口。Vue 组件从创建、挂载到销毁会经历一系列阶段,每个阶段都提供钩子让我们插入代码,统称生命周期钩子。本节以"进入详情页拉取文章数据"为例,讲清常用钩子与请求时机。
组件的一生:常用钩子一览
组合式 API 用 onXxx 函数注册钩子,最常用的有:
onBeforeMount:组件渲染到页面前触发,此时 DOM 还没生成。onMounted:组件挂载完成、DOM 已就绪,请求数据的最佳时机。onBeforeUnmount:组件即将销毁,可清理定时器、取消请求。onUnmounted:组件已销毁。
在 onMounted 中请求数据
以 axios 请求文章详情为例:
<!-- PostDetail.vue -->
<script setup>
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import axios from 'axios'
const route = useRoute()
const post = ref(null) // 文章数据,初始为空
const loading = ref(true) // 是否正在加载
onMounted(async () => {
// 组件挂载后立刻请求,:id 来自路由参数
const { data } = await axios.get(`/api/posts/${route.params.id}`)
post.value = data
loading.value = false
})
</script>
<template>
<p v-if="loading">加载中...</p>
<article v-else>
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
</article>
</template>
运行后页面先显示"加载中...",接口返回后渲染出标题与正文。
用 loading / error 管理请求状态
真实请求可能失败,用三个响应式状态区分界面三种情况:
const post = ref(null)
const loading = ref(true)
const error = ref('') // 错误信息
async function loadPost() {
try {
const { data } = await axios.get('/api/posts/1')
post.value = data
} catch (e) {
error.value = '文章加载失败,请稍后重试' // 出错提示
} finally {
loading.value = false // 无论成败都结束加载态
}
}
模板里用 v-if="loading"、v-else-if="error"、v-else 三选一渲染,页面永远处于明确状态,不会一直转圈或白屏。
路由参数变化时重新请求
若详情页被复用而参数变化,组件不会重新挂载,onMounted 不会再次触发。监听路由参数、变化时重新请求:
import { watch } from 'vue'
// 每次 id 变化都重新拉取数据
watch(() => route.params.id, async (id) => {
const { data } = await axios.get(`/api/posts/${id}`)
post.value = data
}, { immediate: true }) // immediate 让首次进入也立即执行
离开页面时清理:onBeforeUnmount
定时刷新、监听滚动等副作用要记得销毁,否则会内存泄漏:
let timer
onMounted(() => {
timer = setInterval(refreshViewCount, 5000) // 每 5 秒刷新阅读量
})
onBeforeUnmount(() => {
clearInterval(timer) // 组件销毁前清除定时器
})
小结:onMounted 适合发起数据请求,配合 loading/error 让界面清晰;路由参数变化用 watch 重新请求,离开页面用 onBeforeUnmount 清理资源。下一节用 watch 实现博客的实时搜索。