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 辅助,就能写出规范、高效、易维护的代码。

相关推荐
千寻girling2 小时前
不知道 Java 全栈 + AI 编程有没有搞头 ?
前端·人工智能·后端
小码哥_常3 小时前
Android开发:精准捕获应用的前后台行踪
前端
蜡台3 小时前
Vue 打包优化
前端·javascript·vue.js·vite·vue-cli
木斯佳3 小时前
前端八股文面经大全:快手前端一面 (2026-03-29)·面经深度解析
前端·宏任务·原型链·闭包
皙然3 小时前
Redis配置文件(redis.conf)超详细详解
前端·redis·bootstrap
卷帘依旧4 小时前
JavaScript中this绑定问题详解
前端·javascript
dweizhao4 小时前
突发!Claude Code源码泄露了
前端
sunny_4 小时前
💥 Claude Code 源码泄露?我把这个最强 AI Coding Agent 的架构扒干净了
前端·agent·claude
西洼工作室4 小时前
React轮播图优化:通过延迟 + 动画的组合,彻底消除视觉上的闪烁感
前端·react.js·前端框架