AkiraZ's blog

愿键盘的余温传递到更遥远的将来

中文 / English
0%

v-model: 自定义组件的双向数据绑定

v-model语法糖能够实现 Vue 中父组件与子组件之间的双向数据绑定。

很惊讶地发现在最近的 Vue 版本中又得到了更新,似乎变得好用了些。

Vue 3.4+

1
2
3
4
5
6
7
8
9
10
11
12
<!-- Child.vue -->
<script setup>
const model = defineModel();

function update() {
model.value++;
}
</script>

<template>
<div>parent bound v-model is: {{ model }}</div>
</template>
1
2
<!-- Parent.vue -->
<Child v-model="count" />

使用宏 defineModel()来产生一个双向绑定的变量。

如果是多个变量:

  • 使用 defineModel('foo')defineModel('bar')
  • 使用 v-model:foo="val1"v-model:bar="val2"

Vue 3

Vue3.4 以前的实现比较底层,当在父组件中使用 v-model语法糖时,本质上是:

1
2
3
4
5
6
<CustomComponent v-model="foo" />
<!-- 会被编译为 -->
<CustomComponent
:model-value="foo"
@update:model-value="newValue => { foo = newValue }"
/>

所以在子组件实现时,需要手动绑定入参 prop 以及事件,手动写监听以及事件

1
2
3
4
5
6
7
8
const value = computed({
get() {
return props.modelValue;
},
set(value) {
emit("update:modelValue", value);
},
});

Vue 2

Vue 2 中 v-model的行为会有些不同:

1
2
3
<CustomComponent v-model="foo" />
<!-- 会被编译为 -->
<CustomComponent :value="foo" @input="foo=$event.target.value" />

子组件的实现也会有点不同,主要还是变量名和事件的区别

1
2
3
4
5
6
7
8
const value = computed({
get() {
return props.value;
},
set(valueInput) {
emit("input", valueInput);
},
});

Refrence

组件 v-model | Vue.js (vuejs.org)