在 Vue2 中习惯用 computed + getter + setter 实现数据的双向绑定:
javascript
computed: {
someData: {
get() { return this.xxProp },
set(newVal) { emit('input', newVal) }
}
}
结果到 Vue3 发现等价的代码失效了:
javascript
const props = defineProps({
modelValue: {
type: Object,
default: () => ({name: 'xxx'})
}
})
const user = computed({
get => props.modelValue,
set(newVal) => emit('update:modelValue', newVal)
})
// update:modelValue 事件不会触发
user.name = 'abc'
原因是 Vue3 的 computed 无法监听对象属性的修改(而且也没类似 watch 的 deep 选项),因此 Vue2 那套用 computed 实现双向绑定的思路在 Vue3 需要换成 watch 了:
javascript
const props = defineProps({
modelValue: {
type: Object,
default: () => ({name: 'xxx'})
}
})
const user = ref(props.modelValue)
watch(
() => user,
(newVal) => emit('update:modelValue', newVal.value),
{ deep: true }
)
// 触发 update:modelValue
user.name = 'abc'
用 watch 实现双向绑定需要注意如下几点:
- props 的值是 rawValue,没有响应式
- 不要直接修改 props 的属性,因此这里额外定义了一个 user 变量来保存初始的 prop value
- 使用 deep: true 来监听对象属性的变更
如果监听的不是对象,则可以直接用 computed 的方式实现双向绑定
总结
Vue2 和 Vue3 实现对象的双向绑定的思路不同,需要注意二者之间的区别。