

























在 Vue 3 中,useAttrs() 是响应式的。
当你使用 useAttrs() 时,它会返回一个包含组件接收的所有非 props 属性的对象,并且这个对象是响应式的。这意味着:
useAttrs() 返回的对象会自动更新watch 中监听这些属性的变化示例:
import { useAttrs, watch } from 'vue'
export default {
setup() {
const attrs = useAttrs()
// 监听 attrs 的变化
watch(attrs, (newAttrs, oldAttrs) => {
console.log('属性变化了', newAttrs, oldAttrs)
}, { deep: true }) // 深度监听,因为 attrs 是对象
return {
attrs
}
}
}
需要注意的是,useAttrs() 返回的对象是一个 Proxy 对象,它本身是响应式的,但你不应该解构它,因为解构会失去响应性。如果需要使用某个特定属性,应该直接通过 attrs.propName 的方式访问。
在 Vue 3 中,useAttrs() 返回的对象既不是 ref 也不是 shallowRef,而是一个响应式的 Proxy 对象,其特性更接近 reactive 创建的响应式对象,但有一些特殊处理。
具体来说:
不是 ref:ref 用于包装基本类型或对象,访问时需要通过 .value 属性。而 useAttrs() 返回的对象可以直接访问属性(如 attrs.class),无需 .value。
不是 shallowRef:shallowRef 只对顶层值响应,而 useAttrs() 返回的对象对深层属性变化也是响应式的(如父组件传递的 obj 属性内部字段变化时,子组件能感知到)。
特性类似 reactive:
attrs.xxx)但它又不同于普通 reactive 对象:
class、style)和事件监听器示例验证:
import { useAttrs, isRef, isShallowRef, isReactive } from 'vue'
setup() {
const attrs = useAttrs()
console.log(isRef(attrs)) // false
console.log(isShallowRef(attrs)) // false
console.log(isReactive(attrs)) // true(在 Vue 内部实现中基于 reactive)
}
因此,useAttrs() 返回的是一个特殊的响应式对象,行为上更接近 reactive 创建的对象,但专为处理组件属性设计。
在 Vue 3 中,ref 和 reactive 都是用于创建响应式数据的 API,但它们的使用场景和特性有显著区别:
ref:主要用于包装基本数据类型(String、Number、Boolean、Null、Undefined、Symbol),也可以包装对象或数组。
const count = ref(0) // 基本类型
const user = ref({ name: 'Alice' }) // 对象
reactive:只能用于包装对象或数组(引用类型),不能直接包装基本类型。
const user = reactive({ name: 'Alice', age: 20 }) // 对象
const list = reactive([1, 2, 3]) // 数组
ref:通过 .value 访问或修改其内部值(在模板中使用时会自动解包,无需 .value)。
const count = ref(0)
console.log(count.value) // 0
count.value++ // 修改值
// 模板中直接使用
// <div>{{ count }}</div>
reactive:直接通过属性访问或修改,无需 .value。
const user = reactive({ name: 'Alice' })
console.log(user.name) // Alice
user.name = 'Bob' // 修改值
ref:通过包装对象实现响应式(创建一个包含 .value 属性的 Proxy),对于基本类型是直接监听 .value 的变化,对于对象/数组则会内部调用 reactive 处理。
reactive:通过Proxy 代理对象实现响应式,直接监听对象的属性变化(包括新增、删除属性等)。
ref:解构时如果是基本类型,会丢失响应性;如果是对象类型,解构后仍保持响应性(因为内部是 reactive 代理)。
const count = ref(0)
const { value: c } = count // 解构后 c 是非响应式的
reactive:直接解构会丢失响应性(因为解构后得到的是普通值),需要用 toRefs 转换后再解构。
const user = reactive({ name: 'Alice', age: 20 })
const { name, age } = user // 非响应式
正确做法:
import { toRefs } from 'vue'
const { name, age } = toRefs(user) // 保持响应性
优先用 ref 的场景:
优先用 reactive 的场景:
| 特性 | ref |
reactive |
|---|---|---|
| 数据类型 | 基本类型 + 对象/数组 | 仅对象/数组 |
| 访问方式 | 需要 .value(模板中除外) |
直接访问属性 |
| 解构行为 | 基本类型解构会失活 | 直接解构会失活(需 toRefs) |
| 内部实现 | 包装对象 + 内部 reactive |
Proxy 直接代理对象 |
实际开发中,ref 因适用范围更广(可处理所有类型),且在组合式 API 中更易维护,使用频率通常高于 reactive。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。