vue3模板引用ref

1.访问模板引用

要在组合式 API 中获取引用,我们可以使用辅助函数 useTemplateRef() 

只可以在组件挂载后才能访问模板引用

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

// 第一个参数必须与模板中的 ref 值匹配
const input = useTemplateRef('my-input')

onMounted(() => {
  input.value.focus()
})
</script>

<template>
  <input ref="my-input" />
</template>

2. v-for 中的模板引用

当在 v-for 中使用模板引用时,对应的 ref 中包含的值是一个数组,它将在元素被挂载后包含对应整个列表的所有元素

但是ref 数组并不保证与源数组相同的顺序

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

const list = ref([
  /* ... */
])

const itemRefs = useTemplateRef('items')

onMounted(() => console.log(itemRefs.value))
</script>

<template>
  <ul>
    <li v-for="item in list" ref="items">
      {{ item }}
    </li>
  </ul>
</template>

3.组件上的 ref

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

const childRef = useTemplateRef('child')

onMounted(() => {
  // childRef.value 将持有 <Child /> 的实例
})
</script>

<template>
  <Child ref="child" />
</template>

注意:

(1)如果是选项式API或没有使用 <script setup>,父组件对子组件的每一个属性和方法都有完全的访问权.

(2)但是使用了 <script setup> 的组件是默认私有的,也就是父组件无法访问子组件上的任何东西,需要添加defineExpose 宏显式暴露

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

const a = 1
const b = ref(2)

// 像 defineExpose 这样的编译器宏不需要导入
defineExpose({
  a,
  b
})
</script>

<think>嗯,用户问的是Vue3中reactive和ref的用法以及它们在响应式系统中的关系。首先,我需要回顾一下Vue3的响应式系统。Vue3使用Proxy代替了Vue2的Object.defineProperty,所以reactive函数应该是基于Proxy实现的,用于处理对象类型的响应式数据。而ref则是用来包装基本类型,比如数字、字符串,使其变成响应式对象,因为Proxy不能直接代理基本类型。 接下来,我需要解释两者的基本用法。比如,reactive怎么用,传入一个对象,返回Proxy代理的对象。而ref则是返回一个带有value属性的对象,访问时需要.value。这里要注意的是,如果在模板中使用refVue会自动解包,不需要.value,但在JavaScript中需要。 然后,用户可能想知道它们之间的关系。比如,ref也可以包装对象,这时候内部会调用reactive来处理。所以当ref的值是对象时,其实底层用了reactive。这时候可以比较一下两者的使用场景:reactive适合对象、数组等复杂结构,而ref适合基本类型,或者在模板中需要直接引用变量时更方便,比如在setup函数中返回ref变量可以直接在模板使用,而不用.value。 还有,自动解包的情况需要说明,比如当ref作为reactive对象的属性时,会被自动解包,不需要.value。但如果是数组或Map等原生集合类型,则不会自动解包。这时候可能会有一些坑需要注意。 用户可能还会关心如何选择使用reactive还是ref。比如,如果有一个复杂的表单对象,用reactive比较合适;而单个的数值或字符串用ref更直接。此外,组合式API中经常使用ref,尤其是在逻辑复用的时候,因为ref更容易在函数之间传递和返回。 另外,可能需要提到一些常见问题,比如为什么有时候修改了reactive的对象,视图没有更新?可能是因为直接替换了整个对象,导致响应式丢失,这时候应该使用Object.assign或者Vue提供的工具函数。或者当动态添加属性时,需要使用set函数,或者直接使用reactive包装后的对象进行赋值。 最后,需要生成相关问题,可能涉及原理,比如Proxy和Reflect的使用,或者与其他响应式函数的比较,比如toRefs的作用,或者Vue3响应式系统的优缺点等。要确保这些问题能够帮助用户进一步理解相关内容。</think>### Vue3响应式系统中reactive与ref的用法及关系 #### 一、核心机制解析 Vue3的响应式系统基于Proxy实现,通过`reactive()`和`ref()`两个核心API建立数据与视图的绑定关系: 1. **`reactive()`** 用于创建对象/数组的深层响应式代理: ```typescript const state = reactive({ count: 0, list: [] }) state.count++ // 触发视图更新 ``` 2. **`ref()`** 主要处理基本类型值(number/string/boolean)的响应式包装: ```typescript const num = ref(0) num.value++ // 通过.value访问值 ``` #### 二、引用关系特点 1. **嵌套转换机制** - ref包装对象时会自动调用reactive: ```typescript const objRef = ref({ a: 1 }) // 等价于reactive({ value: { a: 1 } }) ``` - reactive对象包含ref时会自动解包: ```typescript const state = reactive({ n: ref(5) }) console.log(state.n) // 直接输出5而非ref对象 ``` 2. **模板差异处理** ```vue <template> <!-- reactive直接访问 --> {{ state.count }} <!-- ref自动解包 --> {{ num }} </template> ``` #### 三、使用场景对比 | 特性 | reactive | ref | |--------------------|----------------------------------|----------------------| | 最佳适用类型 | 对象/数组 | 基本类型/组件引用 | | 模板访问方式 | 直接属性访问 | 自动解包 | | 响应式保持方法 | 保持对象引用 | 通过.value赋值 | | 组合式函数返回值 | 需配合toRefs解构 | 直接返回 | #### 四、性能优化实践 1. 使用`shallowRef`避免深层响应: ```typescript const bigData = shallowRef(largeObj) // 仅.value变化触发更新 ``` 2. 冻结非响应数据: ```typescript const config = reactive(Object.freeze({ apiUrl: &#39;...&#39; })) ``` 3. 动态属性添加的正确方式: ```typescript // 错误方式(丢失响应性) state.newProp = &#39;value&#39; // 正确方式 set(state, &#39;newProp&#39;, &#39;value&#39;) ``` [^1]: Vue3响应式系统通过Proxy实现深层数据追踪,这是与Vue2的核心差异点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值