Vue3 中的 ref、模板引用和 defineExpose 详解

一、ref 基础

在 Vue3 中,ref 是一个非常重要的响应式 API,它用于创建一个响应式的引用。

1.1 ref 的基本用法

javascript

javascript 复制代码
import { ref } from 'vue';

const count = ref(0); // 创建一个响应式引用,初始值为0

console.log(count.value); // 访问值需要使用 .value
count.value++; // 修改值

特点:

  • ref 可以包装任何类型的值,使其变成响应式

  • 在 JavaScript 中访问或修改值时需要使用 .value

  • 在模板中使用时不需要 .value,Vue 会自动解包

1.2 为什么需要 ref

Vue3 使用 Proxy 实现响应式,但 Proxy 无法直接代理原始值(如 number, string 等)。ref 通过将这些值包装在一个对象中,解决了这个问题。

二、模板引用

模板引用是指直接在模板中访问 DOM 元素或组件实例的能力。

2.1 基本模板引用

html

html 复制代码
<template>
  <input ref="inputRef" type="text" />
</template>

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

const inputRef = ref(null); // 必须与模板中的 ref 同名

onMounted(() => {
  inputRef.value.focus(); // 在挂载后自动聚焦
});
</script>

要点:

  1. 声明一个与模板中 ref 同名的响应式引用

  2. 在组件挂载后,inputRef.value 将指向 DOM 元素

  3. 只能在组件挂载后访问 ref 的值

2.2 在 v-for 中使用模板引用

html

html 复制代码
<template>
  <ul>
    <li v-for="item in list" :key="item.id" ref="itemRefs">
      {{ item.text }}
    </li>
  </ul>
</template>

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

const list = ref([
  { id: 1, text: 'Item 1' },
  { id: 2, text: 'Item 2' }
]);

const itemRefs = ref([]);

onMounted(() => {
  console.log(itemRefs.value); // 包含所有 li 元素的数组
});
</script>

注意: 在 v-for 中使用 ref 时,ref 的值将是一个包含所有元素的数组。

三、组件引用与 defineExpose

3.1 引用子组件

html

html 复制代码
<!-- Parent.vue -->
<template>
  <Child ref="childRef" />
</template>

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

const childRef = ref(null);

onMounted(() => {
  console.log(childRef.value); // 子组件实例
});
</script>

3.2 使用 defineExpose 暴露组件方法

默认情况下,使用 <script setup> 的组件是封闭的 ,父组件无法访问子组件的任何内容。需要使用 defineExpose 显式暴露:

html

html 复制代码
<!-- Child.vue -->
<script setup>
import { ref } from 'vue';

const count = ref(0);

function increment() {
  count.value++;
}

// 暴露给父组件
defineExpose({
  increment,
  count
});
</script>

现在父组件可以访问这些暴露的内容:

javascript

javascript 复制代码
// 在 Parent.vue 中
onMounted(() => {
  childRef.value.increment(); // 调用子组件方法
  console.log(childRef.value.count); // 访问子组件数据
});

3.3 defineExpose 的典型用途

  1. 暴露子组件方法供父组件调用

  2. 暴露子组件状态供父组件访问

  3. 创建可复用的组件逻辑(如表单验证、对话框控制等)

四、最佳实践

  1. 命名规范 :使用有意义的 ref 名称,如 formRef, modalRef

  2. 避免过度使用:优先考虑 props/emit 进行组件通信

  3. null 检查:访问 ref 值前检查是否为 null

  4. 组合式函数:将 ref 逻辑封装到组合式函数中提高复用性

五、总结

  • ref 是 Vue3 响应式系统的核心 API 之一

  • 模板引用可以方便地访问 DOM 元素或组件实例

  • defineExpose 用于控制子组件向父组件暴露的内容

  • 合理使用这些特性可以创建更灵活、更易维护的组件

相关推荐
J***Q2928 小时前
Vue数据可视化
前端·vue.js·信息可视化
JIngJaneIL8 小时前
社区互助|社区交易|基于springboot+vue的社区互助交易系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·社区互助
ttod_qzstudio9 小时前
深入理解 Vue 3 的 h 函数:构建动态 UI 的利器
前端·vue.js
芳草萋萋鹦鹉洲哦9 小时前
【elemen/js】阻塞UI线程导致的开关卡顿如何优化
开发语言·javascript·ui
_大龄10 小时前
前端解析excel
前端·excel
1***s63210 小时前
Vue图像处理开发
javascript·vue.js·ecmascript
一 乐10 小时前
应急知识学习|基于springboot+vue的应急知识学习系统(源码+数据库+文档)
数据库·vue.js·spring boot
槁***耿10 小时前
JavaScript在Node.js中的事件发射器
开发语言·javascript·node.js
一叶茶10 小时前
移动端平板打开的三种模式。
前端·javascript
前端大卫10 小时前
一文搞懂 Webpack 分包:async、initial 与 all 的区别【附源码】
前端