torefs能守住响应性,因其将响应式对象的每个属性转为独立ref,确保解构后仍可被v-model绑定和触发更新;三步用法:①用泛型+torefs安全解构props;②模板中直接绑定ref;③配合useattrs透传非props属性。

直接用 toRefs 做二次封装,不是为了“炫技”,而是为了解决一个实际痛点:当把第三方组件(比如 Element Plus 的 ElInput)包裹一层后,父组件传进来的响应式 props(如 v-model:value、:disabled、:clearable)如果只是简单解构或赋值,很容易丢失响应性——尤其在组合式 API 中,解构会切断响应式连接。
为什么 toRefs 能守住响应性?
toRefs 的核心作用,是把一个响应式对象(reactive 或 ref 包裹的值)里的每个属性,都转成独立的 ref。这样即使你把它们解构出来、传给子组件、或者在模板中直接使用,背后的依赖追踪依然有效。
比如你封装 MyInput 时接收了 modelValue 和 disabled,如果直接写 const { modelValue, disabled } = props,那这两个变量就只是普通值,不再是响应式引用。而 toRefs(props) 会确保 modelValue 是一个真正的 Ref,能被 v-model 正确绑定、能触发视图更新。
怎么用?三步到位
① 接收并透传 props,优先用 toRefs 处理
- 不用
defineProps({ modelValue: String })单独声明每个 prop(易漏、难维护) - 改用泛型 +
toRefs安全解构:
<script setup lang="ts"></script>
import { toRefs } from 'vue'
import { ElInput } from 'element-plus'
// 接收所有未声明的 props(含 v-model 的 modelValue、事件等)
const props = defineProps()
// ✅ 用 toRefs 保住每个 prop 的响应性
const { modelValue, disabled, clearable } = toRefs(props)
② 模板中直接绑定,不手动解包
-
v-model:value="modelValue"中的modelValue是 ref,Vue 自动调用.value - 布尔属性如
:disabled="disabled"也能正确响应变化
v-model:value="modelValue"
:disabled="disabled"
:clearable="clearable"
v-bind="$attrs"
/>
③ 配合 useAttrs 补全非 props 属性
-
$attrs会包含未被defineProps声明的属性(如data-test-id、tabindex),必须透传 - 但注意:
modelValue、onUpdate:modelValue这类 v-model 相关内容默认不在$attrs中,所以必须显式绑定
避坑提醒:哪些情况 toRefs 不够用?
• 需要监听 prop 变化做副作用:比如 watch(modelValue, ...),这时 modelValue 是 ref,没问题;但若你用了 watch(() => props.modelValue, ...),也行,只是不如直接 watch ref 清晰。
• 要合并多个响应式源:比如表单校验状态既要读 props.rules,又要读内部 localRules,那就得用 computed 合并,toRefs 不负责这个。
• 第三方组件不支持 ref 绑定:极少数 UI 库组件(尤其老版本)可能没实现 expose 或对 ref 处理不完善,此时需配合 defineExpose 手动暴露方法,toRefs 仅管 props。
响应式不是靠“猜”,而是靠机制。toRefs 就是 Vue 3 组合式 API 里守住 props 响应链最轻量、最可靠的一环——它不增加复杂度,只补上容易断掉的那一扣。









