Vue 3.5.13 中 `defineModel` 的局限性及解决方案
目录:
- 问题描述
- 解决方案
- ✅ 方案一:重新赋值整个数组或对象
- ✅ 方案二:使用
watch
监听外部 props 变化并同步本地状态 - ✅ 方案三:使用
ref
+v-model
显式管理
- 最佳实践建议
- 总结
在 Vue 3.5 版本中引入的 defineModel
是一种简化父子组件之间双向绑定的方式,它替代了 Vue 2 中的 .sync
和 Vue 3 中手动使用 v-model
的方式。然而,在实际开发中我发现 defineModel
在某些场景下存在一定的局限性。
问题描述
当子组件使用 defineModel
接收父组件传递的响应式数据时,如果直接操作数组索引(如 model.value[index] = newValue
),Vue 并不会触发视图更新。这主要是因为 defineModel
返回的是一个 ref 包装后的响应式引用,而数组的索引赋值并不会触发 ref 的 .value
变化,因此无法被 Vue 检测到。
此外,若父组件传入的属性本身是非响应式的(例如通过 toRaw
或 JSON.parse(JSON.stringify(...))
转换后的对象),也会导致子组件中的 defineModel
无法正确追踪变化,从而影响视图更新。
解决方案
✅ 方案一:重新赋值整个数组或对象
为了确保 Vue 能检测到变化,可以采用“重新赋值”的方式来更新整个数组或对象:
<script setup>
const model = defineModel('model', [])// 修改某个元素的值后,重新赋值整个数组
model