Vue3 模板引用实战:useTemplateRef 与 ref 的 3 种 DOM 操作模式 Vue3 模板引用实战useTemplateRef 与 ref 的 3 种 DOM 操作模式在 Vue3 的 Composition API 中模板引用Template Refs是连接响应式数据与真实 DOM 的桥梁。本文将深入探讨如何利用useTemplateRefVue 3.5和传统ref实现三种典型场景的 DOM 操作帮助开发者突破虚拟 DOM 的限制直接与原生 DOM 交互。1. 自动聚焦输入框交互体验的起点表单交互中自动聚焦是提升用户体验的常见需求。传统实现需要手动调用focus()而 Vue3 提供了更优雅的解决方案。1.1 useTemplateRef 实现推荐script setup import { useTemplateRef, onMounted } from vue const inputRef useTemplateRef(input-field) onMounted(() { inputRef.value?.focus() }) /script template input refinput-field placeholder自动获得焦点 / /template关键点解析useTemplateRef的参数需与模板中的ref值严格匹配TypeScript 会自动推断inputRef.value的类型为HTMLInputElement?.可选链操作符避免未挂载时的空值错误1.2 传统 ref 实现script setup import { ref, onMounted } from vue const inputRef refHTMLInputElement | null(null) onMounted(() { inputRef.value?.focus() }) /script template input refinputRef / /template对比分析特性useTemplateRef传统 ref类型推断自动需手动声明命名一致性强制匹配自由命名版本要求Vue ≥3.5所有版本模板 ref 值字符串变量引用提示在需要兼容旧版本或复杂命名场景下传统 ref 更具灵活性而在 Vue 3.5 项目中useTemplateRef能提供更好的开发体验。2. 集成第三方图表库突破虚拟 DOM 的限制当集成 ECharts、D3.js 等需要直接操作 DOM 的库时模板引用成为必要手段。下面以 ECharts 为例2.1 基础集成模式script setup import { useTemplateRef, onMounted, watch } from vue import * as echarts from echarts const chartRef useTemplateRef(chart-container) let chartInstance: echarts.ECharts | null null onMounted(() { if (chartRef.value) { chartInstance echarts.init(chartRef.value) renderChart() } }) function renderChart() { chartInstance?.setOption({ xAxis: { type: category, data: [Mon, Tue, Wed] }, yAxis: { type: value }, series: [{ data: [120, 200, 150], type: bar }] }) } /script template div refchart-container stylewidth: 600px; height: 400px;/div /template2.2 响应式适配方案当图表需要响应数据变化时const props defineProps{ data: number[] }() watch(() props.data, (newData) { chartInstance?.setOption({ series: [{ data: newData }] }) }, { deep: true })性能优化技巧使用shallowRef避免不必要的深度响应通过ResizeObserver实现容器自适应在onUnmounted中调用dispose()释放资源import { shallowRef, onUnmounted } from vue const chartInstance shallowRefecharts.ECharts | null(null) onUnmounted(() { chartInstance.value?.dispose() })3. 动态测量元素尺寸响应式布局的核心实现响应式布局常需要获取元素的实际尺寸。传统方案依赖全局事件而 Vue3 的组合式 API 提供了更模块化的解决方案。3.1 基础尺寸测量script setup import { useTemplateRef, ref, onMounted } from vue const containerRef useTemplateRef(measurable) const dimensions ref({ width: 0, height: 0 }) onMounted(() { if (containerRef.value) { dimensions.value { width: containerRef.value.offsetWidth, height: containerRef.value.offsetHeight } } }) /script template div refmeasurable classresizable-box 当前尺寸{{ dimensions.width }} × {{ dimensions.height }} /div /template3.2 响应式尺寸监听通过组合式函数封装可复用的尺寸监听逻辑// useElementSize.ts import { ref, onMounted, onUnmounted } from vue export function useElementSize(targetRef: RefHTMLElement | null) { const width ref(0) const height ref(0) let observer: ResizeObserver | null null onMounted(() { if (targetRef.value) { observer new ResizeObserver((entries) { const entry entries[0] width.value entry.contentRect.width height.value entry.contentRect.height }) observer.observe(targetRef.value) } }) onUnmounted(() { observer?.disconnect() }) return { width, height } }使用示例script setup import { useTemplateRef } from vue import { useElementSize } from ./useElementSize const containerRef useTemplateRef(responsive-container) const { width, height } useElementSize(containerRef) /script template div refresponsive-container 容器实时尺寸{{ width }} × {{ height }} /div /template4. 高级模式ref 的函数式用法Vue3 支持更灵活的函数式 ref特别适合动态 ref 和组件库开发场景。4.1 动态元素引用script setup import { ref } from vue const items ref([1, 2, 3]) const itemRefs refHTMLElement[]([]) function setItemRef(el: HTMLElement | null, index: number) { if (el) itemRefs.value[index] el } /script template div v-for(item, index) in items :keyitem div :refel setItemRef(el, index)Item {{ item }}/div /div /template4.2 组件方法暴露子组件通过defineExpose暴露方法!-- ChildComponent.vue -- script setup const sayHello () console.log(Hello from child!) defineExpose({ sayHello }) /script父组件通过 ref 调用script setup import { ref } from vue import ChildComponent from ./ChildComponent.vue const childRef refInstanceTypetypeof ChildComponent() function triggerChild() { childRef.value?.sayHello() } /script template ChildComponent refchildRef / button clicktriggerChild调用子组件方法/button /template类型安全提示使用InstanceTypetypeof Component获取组件实例类型通过defineExpose明确暴露的接口可选链操作符避免未定义错误在实际项目中合理选择模板引用模式能显著提升代码的可维护性。对于简单场景useTemplateRef提供了开箱即用的便利复杂场景下组合式函数封装和函数式 ref 能带来更大的灵活性。