生命周期与模板 ref
约 807 字大约 3 分钟
布欧-Lewyon
2026-05-15
首页 › Vue › Composition API › 生命周期与模板 ref
生命周期钩子
Options API vs Composition API 对照
实际用法
<script setup>
import { ref, onMounted, onUnmounted, onBeforeMount, onUpdated, onActivated, onDeactivated } from 'vue'
const count = ref(0)
// 组件挂载到 DOM 后
onMounted(() => {
console.log('组件已挂载,DOM 可访问')
})
// 组件即将卸载
onUnmounted(() => {
console.log('组件即将卸载,清理定时器/事件')
clearInterval(timer)
})
// 组件更新后
onUpdated(() => {
console.log('组件已更新,DOM 已同步')
})
// keep-alive 激活时
onActivated(() => {
console.log('组件被重新激活')
})
// keep-alive 停用时
onDeactivated(() => {
console.log('组件被停用')
})
</script>setup 与 Options 生命周期的对应
| setup 钩子 | Options API | 时机 |
|---|---|---|
| 无(代码直接写在顶层) | setup() | 组件创建前,此时 props/context 可用 |
| 无 | beforeCreate | 实例初始化前 |
| 无 | created | 实例初始化完成 |
onBeforeMount | beforeMount | DOM 渲染前 |
onMounted | mounted | DOM 渲染完成 |
onBeforeUpdate | beforeUpdate | 数据变化,DOM 更新前 |
onUpdated | updated | DOM 更新完成 |
onBeforeUnmount | beforeUnmount | 组件卸载前 |
onUnmounted | unmounted | 组件卸载后 |
onActivated | activated | keep-alive 组件激活 |
onDeactivated | deactivated | keep-alive 组件失活 |
onErrorCaptured | errorCaptured | 子组件错误被捕获 |
模板 ref(template ref)
在 Composition API 中获取 DOM 或组件实例。
获取 DOM 元素
<script setup>
import { ref, onMounted } from 'vue'
// 变量名必须与模板中的 ref 属性值一致
const inputEl = ref(null)
onMounted(() => {
// inputEl.value 就是 <input> DOM 元素
inputEl.value.focus()
})
</script>
<template>
<input ref="inputEl" type="text" />
</template>获取子组件实例
<!-- Child.vue -->
<script setup>
import { ref } from 'vue'
const internalCount = ref(0)
function reset() {
internalCount.value = 0
}
// 默认子组件的所有顶层绑定都不会被父组件 ref 访问到
// 需要显式暴露
defineExpose({ reset })
</script><!-- Parent.vue -->
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const childRef = ref(null)
function callChildReset() {
childRef.value.reset() // ✅ 调用子组件的 reset 方法
}
</script>
<template>
<Child ref="childRef" />
<button @click="callChildReset">重置子组件</button>
</template>函数式 ref
除了字符串 ref="inputEl",还可以用函数:
<script setup>
let inputEl = null
function setInputRef(el) {
if (el) {
inputEl = el
inputEl.focus()
}
}
</script>
<template>
<input :ref="setInputRef" />
</template>v-for 中的 ref
<script setup>
import { ref, onMounted } from 'vue'
const items = ref([1, 2, 3])
const itemRefs = ref([])
onMounted(() => {
console.log(itemRefs.value) // [li, li, li]
})
</script>
<template>
<ul>
<li v-for="item in items" ref="itemRefs" :key="item">
{{ item }}
</li>
</ul>
</template>Vue 3
v-for中的 ref 会自动填充为数组,不需要再手动操作。
实战:自动聚焦 + 防抖搜索
<script setup>
import { ref, onMounted, watch } from 'vue'
const searchInput = ref(null)
const query = ref('')
const results = ref([])
onMounted(() => {
searchInput.value?.focus()
})
// 300ms 防抖搜索
watch(query, (val) => {
const timer = setTimeout(async () => {
results.value = await fetch(`/api/search?q=${val}`).then(r => r.json())
}, 300)
onUnmounted(() => clearTimeout(timer))
})
</script>
<template>
<input ref="searchInput" v-model="query" placeholder="搜索..." />
<ul>
<li v-for="item in results" :key="item.id">{{ item.name }}</li>
</ul>
</template>小结
| 内容 | 要点 |
|---|---|
| 生命周期钩子 | onMounted / onUnmounted / onUpdated / onActivated 等 |
| setup 执行时机 | 在 beforeCreate 之前,this = undefined |
| 模板 ref | 获取 DOM 或组件实例,变量名与 ref="" 一致 |
| defineExpose | 显式暴露子组件属性和方法 |
| v-for ref | 自动填充为数组 |
上一节:computed 与 watch 下一节:组合函数(Composables)
