vue3 中的 v-model
在原生组件中使用 v-model
1
| <input v-model="name" />
|
v-model 是本质上是一个语法糖,上面的代码其实等价于下面这段 (编译器会对 v-model
进行展开):
1 2 3 4
| <input :value="name" @input="name = $event.target.value" />
|
这样最简单的一个双向绑定就实现了,在输入框里更改内容,setup 中的 name 也会改变,数据改变视图也会相应改变
在自定义组件中使用 v-model
1 2 3 4 5 6 7 8
| <child v-model="age" />
<child :modelValue="age" @update:modelValue="newValue => age = newValue" />
|
1 2 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
事件更新父组件值:
1 2 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 本质
1 2 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
了
1 2 3 4
| <my-component v-model:first-name="first" v-model:last-name="last" />
|
1 2
| const first = ref('王'); const last = ref('羲之');
|
1 2 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>
|
1 2 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