本章节我们用 “从特殊到一般” 的推演法,分析 Vue3 中 v-model 语法糖的基本原理,以便我们更好地理解和应用它,具体拆分过程如下:
语法糖版
v-model 的核心要求
- Prop 接收:子组件需要通过 prop.modelValue 接收父组件传递的值
- 事件触发:子组件需要触发
update:modelValue
事件来通知父组件值的改变
其实 Vue3 中,v-model="counter" 中,默认绑定的属性是 modelValue。
绑定自定义属性 :aaa
现在我们修改这个属性,将 modelValue 改为 aaa,功能依然正常。
拆分 v-model:aaa
现在我们修改父组件中调用子组件的地方,对于带参数的 v-model:aaa
拆分后等价于:
- prop 绑定:
:xxx="父组件数据"
- 事件监听:
@update:xxx="父组件数据 = $event"
替换自定义方法 @update:aaa
现在我们修改 子传父时,在子组件中绑定的事件回调名称,把默认的 @update:aaa,改为别的名称,依然生效:
拓展:Vue2 中,自定义组件的 v-model 语法糖:
父组件:
<template>
<div>
<CustomCounter v-model="count" />
<p>当前计数: {{ count }}</p>
</div>
</template>
<script>
import CustomCounter from './CustomCounter.vue'
export default {
components: {
CustomCounter
},
data() {
return {
count: 0
}
}
}
</script>
子组件:
默认 value 属性 + input 事件
<template>
<div>
<button @click="decrement">-</button>
<span>{{ value }}</span>
<button @click="increment">+</button>
<button @click="reset">重置</button>
</div>
</template>
<script>
export default {
name: 'CustomCounter',
props: {
value: {
type: Number,
default: 0
}
},
methods: {
increment() {
this.$emit('input', this.value + 1);
},
decrement() {
this.$emit('input', this.value - 1);
},
reset() {
this.$emit('input', 0);
}
}
}
</script>