Vue中如何结合v-model与Composition API(provide/inject)实现值的展示与双向绑定
你碰到的核心问题其实是Ref对象的自动解包规则——因为你在store里用了toRefs(state)把reactive对象的属性转成了Ref类型,所以userStore.userForm并不是原始的用户对象,而是一个包裹着对象的Ref容器。
问题根源
Vue的模板对Ref对象有自动解包的特性:直接使用单个Ref变量(比如{{ userForm }})时,模板会自动读取它的.value值;但一旦你访问Ref的嵌套属性(比如userForm.firstname),模板就不会自动解包了,必须手动通过.value访问内部值。这就是为什么你写userStore.userForm.value.firstname能显示内容,但直接写userStore.userForm.firstname无效,v-model也无法正常绑定的原因。
解决方案
这里有几种优雅的处理方式,按推荐程度排序:
方案1:在组件setup中解构Ref(最推荐)
在组件的setup函数里把store中的userForm解构出来,模板会自动对单个Ref进行解包,这样就能直接用v-model绑定嵌套属性了:
setup(props, context) { const userStore = inject('userStore'); // 解构出userForm这个Ref对象 const { userForm } = userStore; return { userForm }; }
然后在模板里直接使用:
<div>用户姓名:{{ userForm.firstname }}</div> <input v-model="userForm.firstname" placeholder="请输入姓名">
方案2:手动在模板中指定.value(不推荐,较繁琐)
如果你不想解构,也可以直接在模板里手动访问Ref的.value属性来绑定v-model:
<input v-model="userStore.userForm.value.firstname">
这种方式虽然能工作,但代码不够简洁,而且如果userForm初始值是null的话,还会触发Cannot read properties of null的错误,所以只适合临时测试使用。
方案3:优化store的初始状态(可选)
你当前的state.userForm初始值是null,这会导致在用户对象未被设置前,访问firstname时抛出错误。可以把初始值改成空对象,提前避免这类问题:
// store.js中的state部分 const state = reactive({ userForm: {}, // 改为空对象替代null });
额外提示
你store里的getUserForm计算属性其实有点多余——因为userStore.userForm已经是一个响应式的Ref了,直接使用它就能拿到最新的用户表单数据,不需要额外用computed包装。如果后续需要对用户数据做转换处理,再保留这个计算属性就好。
内容的提问来源于stack exchange,提问作者Jérémie Chazelle

