Vue3 模板引用 (ref):操作 DOM 与子组件实例 从入门到精通

前言

在 Vue 的数据驱动 思想下,我们通常通过修改数据来驱动视图更新,避免直接操作 DOM。但在实际开发中,总会遇到一些非 DOM 不可的场景:比如获取输入框焦点、调用第三方库初始化画布、获取子组件的数据或方法等。

这时候,Vue 提供的模板引用 ref 就派上了用场。

本文将带你系统学习 Vue3 中 ref 的核心用法、操作 DOM、获取/调用子组件实例、与 reactive 区别等知识点,帮你彻底掌握模板引用,写出更优雅的 Vue 代码。

一、什么是模板引用 ref?

简单说:
ref 是 Vue 提供的获取「真实 DOM 元素」或「子组件实例」的方式。

它的核心作用:

  1. 获取原生 DOM 节点(如 input、div、canvas)
  2. 获取子组件实例(调用子组件方法、访问子组件数据)
  3. 配合生命周期函数执行 DOM 操作

注意:Vue3 中 ref 有两个含义:

  1. 响应式引用:定义基础类型响应式数据
  2. 模板引用 :获取 DOM / 子组件
    本文重点讲:模板引用 ref

二、基础用法:获取并操作 DOM

1. 使用步骤(三步)

  1. 给元素添加 ref="名称"
  2. 在 <script setup> 中创建一个同名 ref 对象
  3. 等 DOM 渲染后,通过 .value 获取真实 DOM

2. 实战:获取 input 并自动聚焦

vue 复制代码
<template>
  <!-- 1. 给 DOM 添加 ref 属性 -->
  <input type="text" ref="inputRef" placeholder="自动聚焦" />
</template>

<script setup>
import { ref, onMounted } from 'vue'

// 2. 创建与 ref 同名的响应式变量
const inputRef = ref(null)

// 3. 在挂载完成后操作 DOM(必须在 onMounted 中)
onMounted(() => {
  // 获取真实 DOM:inputRef.value
  inputRef.value.focus()
  console.log('真实 DOM 元素:', inputRef.value)
})
</script>

✅ 关键点:

  • 模板里的 ref 名称 = script 里的变量名
  • 必须在 onMounted 生命周期后才能获取到 DOM
  • 访问方式:ref对象.value

三、进阶用法:获取子组件实例(调用方法/访问数据)

这是组件封装、组件通信 的高频用法:

父组件可以通过 ref 获取子组件实例,直接调用子组件方法、访问子组件数据。

1. 子组件(Child.vue)

必须用 defineExpose 暴露需要让父组件访问的内容!

(Vue3 脚本 setup 默认封闭,不暴露任何内容)

vue 复制代码
<template>
  <div>子组件内容:{{ msg }}</div>
</template>

<script setup>
import { ref } from 'vue'

// 子组件数据
const msg = ref('我是子组件数据')

// 子组件方法
const childFn = () => {
  alert('子组件方法被执行了!')
}

// ✅ 必须暴露:父组件才能获取
defineExpose({
  msg,
  childFn
})
</script>

2. 父组件使用

vue 复制代码
<template>
  <button @click="callChild">调用子组件方法</button>
  <!-- 给子组件添加 ref -->
  <Child ref="childRef" />
</template>

<script setup>
import { ref } from 'vue'
import Child from './Child.vue'

// 子组件实例引用
const childRef = ref(null)

const callChild = () => {
  // 调用子组件方法
  childRef.value.childFn()
  
  // 访问子组件数据
  console.log('子组件数据:', childRef.value.msg)
}
</script>

✅ 核心规则:

  • 子组件必须用 defineExpose 暴露属性/方法
  • 父组件通过 ref.value.xxx 调用
  • 不要滥用:能通过 props / emit 实现就不用 ref

四、v-for 中的多个 ref (批量获取 DOM)

v-for 循环生成的元素,不能用单个 ref,必须用函数 ref 或数组 ref。

实战:批量获取列表 DOM

vue 复制代码
<template>
  <ul>
    <li
      v-for="item in list"
      :key="item"
      :ref="setItemRef"
    >
      {{ item }}
    </li>
  </ul>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const list = ref([1, 2, 3, 4, 5])

// 存放所有 DOM 引用
const itemRefs = ref([])

// 函数 ref:自动把 DOM 推入数组
const setItemRef = (el) => {
  if (el) {
    itemRefs.value.push(el)
  }
}

onMounted(() => {
  console.log('所有 li DOM:', itemRefs.value)
})
</script>

五、重要注意事项(必看!避免踩坑)

1. 访问时机

  • 不能在 setup 同步代码中直接访问
  • 必须在:
    • onMounted
    • 事件处理函数(click 等)
    • nextTick

2. 访问方式

  • DOM / 组件实例 = ref值.value
  • 不能直接用 ref值

3. 子组件必须暴露

  • <script setup> 的组件默认封闭
  • 必须用 defineExpose 暴露方法和数据

4. 不要滥用

  • 能通过数据驱动就不操作 DOM
  • 能通过 props/emit 就不调用子组件实例

六、常见面试题

1. ref 和 reactive 的区别?

  • ref:用于基础类型(string/number/boolean)+ DOM 引用
  • reactive:用于引用类型(对象/数组)

2. 为什么要在 onMounted 中获取 ref?

因为 setup 执行时DOM 还没渲染,必须等挂载完成。

3. 父组件如何调用子组件方法?

  1. 子组件 defineExpose
  2. 父组件用 ref 获取实例
  3. ref.value.方法名()

七、总结

  1. 模板 ref = 获取 DOM / 子组件实例
  2. 用法:ref="名称" → 定义同名 ref → onMounted 使用
  3. 操作 DOM:ref.value.focus() 等
  4. 子组件:必须 defineExpose 暴露
  5. v-for:使用函数 ref 批量存储

结语

模板引用 ref 是 Vue3 必备核心技能,尤其在表单操作、第三方库集成、组件封装中高频使用。

只要记住:数据驱动优先,ref 辅助,就能写出规范、高效、易维护的代码。

相关推荐
程序员Sunday13 小时前
JavaScript 事件循环面试题,宏任务与微任务怎么执行|Sunday面试指南
开发语言·javascript·面试·校招·事件循环·程序员sunday
Setsuna_F_Seiei13 小时前
前端转型 Agent 开发 06 之 Agent Memory 记忆系统(让 Agent 更智能,更懂你)
前端·agent·ai编程
志尊宝13 小时前
Vue3 零基础每日笔记(073):keep-alive 页面缓存实战——列表页返回不丢状态
vue.js·笔记·缓存·#vue #前端 #前端开发·#javascript·#vue.js
zhangzeyuaaa14 小时前
Ruby 多线程、GVL(GIL)与 Mutex 完全指南
开发语言·前端·ruby
默_笙14 小时前
🌊 向量库和 ES 都查不出"关系",我只好给奶茶建了一张人脉网
前端·javascript
优选资讯14 小时前
标签打印软件怎么对接 Excel 数据
前端·excel
思无邪6615 小时前
用 AI 做 JS 逆向:从抓包到复现的完整方法论
开发语言·javascript·人工智能
一个风轻云淡15 小时前
GCC 和 GDB命令简单解读
java·linux·前端
u01110267516 小时前
图片处理接口如何统一错误信息 前端提示与后端错误码设计
前端·状态模式
福兮说16 小时前
浏览器里把 iPhone 的 HEIC 转成 JPG:Chrome 解不开、转完大了七成、拍摄时间全丢,六个坑实测
前端·javascript·图像处理·chrome·ios·iphone·heic