url: /posts/ddbce4f2a23aa72c96b1c0473900321e/
 title: 快速入门Vue模板引用:从收DOM“快递”到调子组件方法,你玩明白了吗?
 date: 2025-11-03T02:55:45+08:00
 lastmod: 2025-11-03T02:55:45+08:00
 author: cmdragon
summary:
 Vue中的模板引用(Template Refs)用于在声明式编程中直接操作DOM或访问子组件实例。通过ref属性标记元素或组件,并在setup中使用同名响应式变量访问。子组件需通过defineExpose暴露内部方法或属性供父组件调用。操作DOM时,应在onMounted或nextTick中确保DOM已渲染。常见应用包括自动聚焦输入框、集成第三方库和动态获取元素尺寸。
categories:
- vue
 
tags:
- 基础入门 
  
- Vue
 
 - 模板引用
 - DOM操作
 - 组件通信
 - nextTick
 - defineExpose
 - 最佳实践
 
 
扫描二维码关注或者微信搜一搜:编程智域 前端至全栈交流与成长
发现1000+提升效率与开发的AI工具和实用程序:https://tools.cmdragon.cn/
一、模板引用的基本概念与用法
在Vue的声明式编程模型中,我们通常不需要直接操作DOM——Vue会根据数据自动更新视图。但有些场景必须直接接触DOM:比如聚焦输入框、获取元素尺寸、集成第三方DOM库(如Chart.js)。这时候,**模板引用(Template Refs)**就成了连接声明式世界与命令式DOM操作的桥梁。
1.1 什么是模板引用?
模板引用是Vue提供的一种标记DOM元素或组件的方式:通过给元素或组件添加ref属性(类似“标签”),我们可以在setup中通过同名的响应式变量,直接访问对应的DOM元素或组件实例。
1.2 如何声明和使用模板引用?
使用模板引用的步骤非常简单,只需两步:
- 在模板中标记元素:给需要引用的元素添加
ref="xxx"属性; - 在
setup中创建响应式变量:用ref(null)创建同名变量,Vue会自动将DOM元素赋值给它。 
注意:模板引用的变量必须用ref(null)初始化(初始值为null),因为Vue会在组件挂载后才将DOM元素赋值给它。
1.3 示例:自动聚焦输入框
下面是一个最常见的场景——页面加载后自动聚焦输入框:
<template>
  <!-- 用ref标记输入框 -->
  <input ref="inputRef" type="text" placeholder="请输入内容" />
</template>
<script setup>
// 1. 导入需要的API:ref(创建响应式变量)、onMounted(生命周期钩子)
import { ref, onMounted } from 'vue'
// 2. 创建响应式变量,初始值为null(此时DOM还未渲染)
const inputRef = ref(null)
// 3. 组件挂载后(DOM已渲染),聚焦输入框
onMounted(() => {
  // inputRef.value 此时指向模板中的<input>元素
  inputRef.value.focus() 
})
</script>
 
代码解释:
ref="inputRef":给输入框贴了个“标签”,告诉Vue“我要引用这个元素”;const inputRef = ref(null):在setup中创建一个“容器”,等待Vue把DOM元素装进来;onMounted:组件挂载完成的生命周期钩子,此时DOM已经渲染完成,inputRef.value不再是null,可以安全调用focus()方法。
二、组件的模板引用与暴露
模板引用不仅能标记DOM元素,还能标记子组件。但组件的引用有个特殊规则:默认情况下,子组件的内部状态和方法是“私有的”,父组件无法直接访问。如果要让父组件调用子组件的方法或访问其内部元素,必须用defineExpose显式暴露。
2.1 引用子组件的默认行为
当你给子组件添加ref属性时,父组件拿到的是子组件的根元素(如果子组件有多个根元素,会报错)。比如:
<!-- ParentComponent.vue -->
<template>
  <!-- 引用子组件 -->
  <ChildComponent ref="childRef" />
</template>
<script setup>
import { ref, onMounted } from 'vue'
import ChildComponent from './ChildComponent.vue'
const childRef = ref(null)
onMounted(() => {
  // childRef.value 指向子组件的根元素(比如<div>)
  console.log(childRef.value) 
})
</script>
 
2.2 暴露子组件内部内容:defineExpose
 
如果父组件需要访问子组件的内部方法或非根元素,子组件必须用defineExpose将这些内容“公开”。defineExpose是Vue 3的内置API,专门用于暴露setup中的内容给父组件。
2.3 示例:父组件调用子组件的方法
假设子组件有一个“点击按钮”的方法,父组件需要直接调用它:
子组件(ChildComponent.vue):
<template>
  <button @click="handleClick">子组件按钮</button>
</template>
<script setup>
// 导入defineExpose API
import { defineExpose } from 'vue'
// 子组件的内部方法
const handleClick = () => {
  console.log('子组件按钮被点击!')
}
// 关键:将handleClick方法暴露给父组件
defineExpose({
  handleClick
})
</script>
 
父组件(ParentComponent.vue):
<template>
  <ChildComponent ref="childRef" />
  <button @click="callChildMethod">调用子组件方法</button>
</template>
<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'
// 引用子组件实例
const childRef = ref(null)
// 父组件调用子组件方法
const callChildMethod = () => {
  // 通过childRef.value访问子组件暴露的handleClick
  childRef.value.handleClick() 
}
</script>
 
效果:点击父组件的“调用子组件方法”按钮,会触发子组件的handleClick,控制台输出“子组件按钮被点击!”。
三、DOM操作的最佳实践
直接操作DOM虽然灵活,但容易破坏Vue的响应式流程。以下是避免踩坑的关键原则:
3.1 何时可以安全操作DOM?
DOM元素只有在组件挂载后才会存在,因此:
- 不要在
setup的顶级 scope 直接访问模板引用(此时xxx.value还是null); - 不要在
onBeforeMount钩子中操作DOM(组件还没挂载,元素未渲染); - 安全时机:
onMounted钩子(组件首次挂载完成)、nextTick(DOM更新后)。 
3.2 nextTick:处理DOM更新后的操作
 
Vue的DOM更新是

                  
                  
                  
                  
最低0.47元/天 解锁文章
                          
                      
      
          
                
                
                
                
              
                
                
                
                
                
              
                
                
              
            
                  
被折叠的  条评论
		 为什么被折叠?
		 
		 
		
    
  
    
  
            


            