vue3 中的 v-model
在原生组件中使用 v-model
| 1
 | <input v-model="name" />
 | 
v-model 是本质上是一个语法糖,上面的代码其实等价于下面这段 (编译器会对 v-model 进行展开):
| 12
 3
 4
 
 | <input:value="name"
 @input="name = $event.target.value"
 />
 
 | 
这样最简单的一个双向绑定就实现了,在输入框里更改内容,setup 中的  name 也会改变,数据改变视图也会相应改变
在自定义组件中使用 v-model
| 12
 3
 4
 5
 6
 7
 8
 
 | <child v-model="age" />
 
 
 <child
 :modelValue="age"
 @update:modelValue="newValue => age = newValue"
 />
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | // child.vue<script setup lang="ts">
 const props = defineProps<{
 modelValue: number;
 }>();
 
 const emit = defineEmits<{
 (e: 'update:modelValue', modelValue: number): void;
 }>();
 
 const changAge = () => {
 emit('update:modelValue', 18);
 };
 </script>
 
 <template>
 <p>{{ props.modelValue }}</p>
 <button @click="changAge">点击按钮(changAge)</button>
 </template>
 
 | 
v-model 用在自定义组件上时,v-model默认绑定的 prop 名是 modelValue
事件也由 @input 更改为@update: modelValue
v-model 的参数
vue3 移除了 model 选项,这样就无法在组件内修改默认 prop 名,如果要修改默认 prop 名,可以通过给 v-model:xxx 指定一个参数来更改名字:
| 1
 | <child v-model:name="name" />
 | 
在这个例子中,子组件应声明一个 name prop,并通过触发 update:name 事件更新父组件值:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | <script setup lang="ts">const props = defineProps<{
 name: string;
 }>();
 
 const emit = defineEmits<{
 (e: 'update:name', name: string): void;
 }>();
 
 const changName = () => {
 emit('update:name', 'mark');
 };
 </script>
 
 <template>
 <p>这是子组件</p>
 <button @click="changName">点击</button>
 </template>
 
 | 
vue3 同时也移除了 .sync 修饰符,我们先来回顾一下.sync 的作用:
.sync 可以简单的理解为:可以同时双向绑定多个 prop,而并不像 v-model 那样,一个组件只能有一个。
.sync 本质
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | <my-component :first-name.sync="first" :last-name.sync="last" />
 
 <my-component
 :first-name="first"
 @update:first-name="(val) => first = val"
 :last-name="last"
 @update:last-name="(val) => last = val"
 >
 
 | 
v-bind.sync 在 2.x 中的使用情况相当混乱, 因为用户以为可以像 v-bind 一样使用它 (完全不看我们在文档中写的). 我认为最好的解释就是:
认为 v-bind:title.sync="title" 是一种具有额外功能的正常绑定是错误的想法, 因为这跟双向绑定完全不同. .sync 修饰符的工作原理就像另一种用于创建双向绑定的语法糖 v-model. 主要区别在于 .sync 可以在单个组件上定义多个双向绑定, 但 v-model 只能定义一个.
那么问题来了: 如果告诉用户不要将 v-bind.sync 认为是 v-bind, 应该把它认为是 v-model, 那它是不是应该成为 v-model 的一部分 ?
…
现在,在 vue3 里,你可以在组件上书写多个 v-model 来替代 .sync 了
| 12
 3
 4
 
 | <my-componentv-model:first-name="first"
 v-model:last-name="last"
 />
 
 | 
| 12
 
 | const first = ref('王');const last = ref('羲之');
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | <script setup lang="ts">
 const props = defineProps<{
 firstName: string;
 lastName: string;
 }>();
 
 const emit = defineEmits<{
 (e: 'update:firstName', firstName: string): void;
 (e: 'update:lastName', lastName: string): void;
 }>();
 
 const changName = () => {
 emit('update:firstName', '李');
 emit('update:lastName', '白');
 };
 </script>
 
 | 
| 12
 3
 4
 
 | <template><p>{{ props.firstName }}{{ props.lastName }}</p>
 <button @click="changName">点击按钮(changName)</button>
 </template>
 
 | 
总结
vue2 和 vue3 中 v-model 区别:
- 在自定义组件中 v-model 默认绑定的 prop 名从 value 变为 modelValue
- 事件名也由 @input更改为@update: modelValue
- vue3 移除了 model 选项,修改默认 prop name 可以通过给 v-model:xxx指定一个参数来更改名字
- vue3 同时也移除了 .sync修饰符,你可以在组件上书写多个 v-model 来替代 .sync