Vue3 中再次封装已支持 v-model 的组件的方式
简介
Vue3 部分 API 进行了升级或改变,对于 v-model 的实现原理是相同的,但语法略微不同。主要有两种方式:
- 通过 prop 和自定义事件
- 通过一个支持 get/set 的计算属性代替 prop
方式1
与老版相同,都是先绑定一个 prop,并在组件内部通过 vue 的自定义事件返回:
子组件(这里将官方示例的默认 prop 名称 modelValue 改成了自定义名称 msg):
<script setup>
defineProps(['msg'])
defineEmits(['update:msg'])
</script>
<template>
<input
:value="msg"
@input="$emit('update:msg', $event.target.value)"
/>
</template>
方式2
子组件:
<script setup>
import { ref, defineProps, defineEmits, computed, } from 'vue'
const props = defineProps(['msg'])
const emit = defineEmits(['update:msg'])
const value = computed({
get() {
return props.msg
},
set(value) {
emit('update:msg', value)
}
})
const title = ref('Hello World!')
</script>
<template>
<h1>这是子组件标题:{{ title }}</h1>
<input v-model="value">
</template>
父组件:
<script setup>
import Comp from './Comp.vue'
import { ref } from 'vue'
const title = ref('Hello World!')
</script>
<template>
<!-- 这里的 :msg 非常重要,如果没有写上,子组件修改了内部值之后,及时成功调用了 emit() 方法,父组件也无法获取到更新值
因为对于组件, v-model 绑定时,默认的 prop 名称是 modelValue ,而不是此处的变量名 title
也就是说,未绑定自定义名称时,子组件内部触发的事件其实是 emit('update:modelValue', newValue) -->
<Comp v-model:msg=title />
<h1>这是父组件标题:{{ title }}</h1>
</template>
简单对比
方式1与老版思路基本一致,但新增了默认的 prop 名称是 modelValue,且触发事件必须使用 update:modelValue 这种形式的限制。方式2则是通过一个计算属性,代替 prop 传递初始值并向外触发自定义事件,好处是原先的组件可以继续使用 v-model,坏处是代码量比方式1稍多。
方式1由于使用 prop 作为数据的来源,而 prop 是只能单向传递数据的,不允许修改其值,因此不能在原先的组件上直接使用 v-model 绑定,必须拆分 v-bind 和 emit 这两个过程。

浙公网安备 33010602011771号