useTemplateRef和ref的区别
useTemplateRef 和 ref 都是用来创建响应式引用(Reactive References)的,但在 Vue 3.5+ 中,useTemplateRef 是一个专门为模板引用(Template Refs)设计的组合式 API (Composable) 。让我们详细对比一下它们:
ref
-
核心功能:
ref是 Vue 最基础的响应式系统 API 之一。它可以包装任何值(原始类型、对象、DOM 元素、组件实例等),使其成为响应式的。 -
用途广泛:
- 存储和响应式地更新本地组件状态(如
count = ref(0))。 - 作为模板引用(虽然在 3.5+ 之前常用)。
- 在任何需要响应式引用的地方。
- 存储和响应式地更新本地组件状态(如
-
在模板引用中的用法 (旧方式) :
<template> <div ref="divRef">Hello World</div> </template> <script setup> import { ref, onMounted } from 'vue'; const divRef = ref(null); // 创建一个 ref onMounted(() => { // divRef.value 现在是 DOM 元素 console.log(divRef.value); // <div>Hello World</div> divRef.value.focus(); // 例如,聚焦到元素上 }); </script>-
问题: 在
<script setup>中,divRef会暴露给模板,即使你只想在脚本内部使用它。这可能会污染模板的上下文。
-
问题: 在
useTemplateRef (Vue 3.5+)
-
核心功能: 专门用于获取对模板中元素或组件的引用。它返回一个getter 函数,而不是一个 ref 对象。
-
目的: 解决
ref作为模板引用时暴露到模板上下文的问题,提供更清晰、更符合直觉的 API。 -
用途: 仅用于模板引用。
-
返回值: 一个 getter 函数,调用它会返回最新的模板引用值。这个函数本身是响应式的,但其返回值(即引用的元素或组件实例)不是。
-
优势:
-
不污染模板上下文:
useTemplateRef返回的 getter 不会被自动暴露到模板中,保持了模板上下文的整洁。 -
意图明确: 使用
useTemplateRef明确表示你正在创建一个模板引用,提高了代码的可读性。 -
类型推断: 在 TypeScript 中,
useTemplateRef能提供更精确的类型推断。
-
不污染模板上下文:
-
在模板引用中的用法 (新方式) :
<template> <div ref="divRef">Hello World</div> </template> <script setup> import { useTemplateRef, onMounted } from 'vue'; // useTemplateRef 返回一个 getter 函数 const getDivRef = useTemplateRef('divRef'); onMounted(() => { // 调用 getter 函数获取 DOM 元素 console.log(getDivRef()); // <div>Hello World</div> getDivRef()?.focus(); // 例如,聚焦到元素上 }); </script>- 注意:在
ref指令中使用的字符串(如'divRef')必须与useTemplateRef的参数完全匹配。 -
getDivRef()返回的是实际的 DOM 元素或组件实例,如果元素未挂载,则可能返回null或undefined。
- 注意:在
对比总结
| 特性 | ref |
useTemplateRef |
|---|---|---|
| 主要目的 | 创建通用的响应式引用 | 专门用于模板引用 |
| 返回值 | 一个包含 .value 属性的 ref 对象 |
一个 getter 函数 |
| 模板暴露 | 会暴露到模板上下文(如果在 <script setup> 中定义) |
不会暴露到模板上下文 |
| 类型推断 | 一般 | 更好(尤其是在 TS 中) |
| 意图表达 | 通用,需看上下文 | 明确 |
| Vue 版本要求 | 3.0+ | 3.5+ |
| 何时使用 | 通用响应式状态、旧项目中的模板引用 | Vue 3.5+ 项目中的模板引用 (推荐) |
结论
- 对于模板引用(获取 DOM 元素或子组件实例),强烈推荐在 Vue 3.5+ 项目中使用
useTemplateRef。它更清晰、更安全、类型更友好。 - 对于通用的响应式状态管理(如计数器、布尔标志等),继续使用
ref。 - 在你的项目中,如果已经升级到了 Vue 3.5 或更高版本,并且需要获取模板引用,请优先考虑
useTemplateRef。