Vue2与3 v-model
v-model
其实做了两个事情:
- v-bind绑定value属性的值;
- v-on绑定input事件监听到函数中,函数会获取最新的值赋值到绑定的属性中;
在原生表单元素中
1 | <input v-model="serchText"> |
等价于:
1 | <input :value="serchText" @input="serchText = $event.target.value"> |
在自定义组件中
在 Vue 2 中,自定义组件的 v-model 是一种常用的父子组件双向数据绑定方式。它的本质是对 value prop 和 input 事件的语法糖封装。
工作原理
v-model 默认会绑定到子组件的
value
prop 上。当子组件需要修改这个值时,需要通过
$emit('input', newValue)
事件通知父组件更新。
子组件定义:
1 | <!-- child.vue --> |
父组件使用:(这样,msg 就和 MyInput 组件的输入框实现了双向绑定。)
1 | <template> |
model
如果你想自定义 prop 名和事件名,可以用 model 选项:
1 | export default { |
这样父组件的 v-model 会变成 :checked=”xxx” @change=”xxx = $event”
例如:(父组件代码同上)
1 | <!-- child.vue --> |
总结
Vue2 自定义组件的 v-model 默认绑定 value prop 和 input 事件。
子组件通过 $emit(‘input’, newValue) 通知父组件更新。
可以通过 model 选项自定义 prop 和事件名。
.sync
修饰符
在 Vue 2 中,.sync 是一个用于父子组件之间双向绑定 prop 的语法糖修饰符。
作用
- 通常,父组件通过 prop 向子组件传递数据,子组件不能直接修改这个 prop。如果子组件需要修改父组件的数据,通常需要通过 $emit 事件通知父组件,然后父组件再修改传递给子组件的 prop。
- .sync 修饰符简化了这个过程,让父组件可以更方便地实现 prop 的双向绑定。
使用方式
假设有一个子组件 child,它有一个 prop 叫 value:
1 | <!-- 父组件模板 --> |
使用 .sync 后,可以这样写 (等价于上面那种写法):
1 | <child :value.sync="parentValue"></child> |
此时,子组件只需要这样触发事件,父组件的 parentValue 就会自动更新:
1 | this.$emit('update:value', newValue) |
总结
- .sync 是 Vue 2 的语法糖,用于简化 prop 的双向绑定。
- 实现原理是监听 update:propName 事件,并自动更新父组件的数据。
- 在 Vue 3 中,推荐使用 v-model 代替 .sync。
相较于vue2
- prop:
value
->modelValue
; - 事件:
input
->update:modelValue
; v-bind
的.sync
修饰符和组件的model
选项已移除- 新增 支持多个v-model
- 新增 支持自定义 修饰符 Modifiers
即父组件中的 v-model="foo"
将被编译为:
1 | <!-- Parent.vue --> |
案例
1 | // 父组件 |
1 | // 子组件 |
v-model参数
默认情况下,使用v-model
,相当于传递给组件一个modelValue
,如上所示,我们可以修改这些名称,并将参数传递
1 | <MyComponent v-model:title="bookTitle" /> |
这时候,组件中需要接收title
值和update:title
事件
1 | <script setup lang="ts"> |
defineModel
从 Vue 3.4 开始,推荐的实现方式是使用 defineModel()
宏:
defineModel()
返回的值是一个 ref。它可以像其他 ref 一样被访问以及修改,不过它能起到在父组件和当前变量之间的双向绑定的作用:
- 它的
.value
和父组件的v-model
的值同步; - 当它被子组件变更了,会触发父组件绑定的值一起更新。
父组件可以用 v-model
绑定一个值:
1 | <!-- Parent.vue --> |
1 | <!-- Child.vue --> |