defineModel
defineModel
是 Vue3.4 及以上版本中引入的一个宏,用于简化组件之间的双向数据绑定。以下是关于 defineModel
的一些关键点:
基本概念
- 引入背景:在 Vue3.4 之前,实现组件间的双向绑定需要手动定义
modelValue
属性,并通过update:modelValue
事件来更新父组件的值,这种方式较为繁琐。defineModel
的引入使得这一过程更加简洁。 - 使用场景:适用于需要在子组件中通过父组件的
v-model
实现双向绑定的情况。
使用方法
-
基础用法:在子组件中直接使用
defineModel()
定义一个模型,并在模板中通过v-model
绑定到输入框等元素上。例如:<!-- 子组件 --> <template><input v-model="model" /> </template> <script setup> const model = defineModel(); </script>
在父组件中,使用
v-model
绑定到一个变量上:<!-- 父组件 --> <template><ChildComponent v-model="value" /> </template> <script setup> import { ref } from 'vue'; const value = ref(''); </script>
这样,子组件中的
model
和父组件中的value
就实现了双向绑定,当子组件中输入框的值改变时,父组件中的value
也会同步更新。 -
定义类型和默认值:可以为
defineModel
指定类型和默认值,例如:<script setup> const model = defineModel({ type: String, default: "20" }); </script>
这里的
model
是一个字符串类型的ref
,并且有默认值 “20”。 -
多个
v-model
绑定:如果需要在子组件中处理多个双向绑定,可以为每个模型定义一个ref
,例如:<!-- 子组件 --> <template><input v-model="firstName" /><input v-model="lastName" /> </template> <script setup> const firstName = defineModel('firstName'); const lastName = defineModel('lastName'); </script>
在父组件中,使用多个
v-model
进行绑定:<!-- 父组件 --> <template><ChildComponentv-model:first-name="firstName"v-model:last-name="lastName"/> </template> <script setup> import { ref } from 'vue'; const firstName = ref(''); const lastName = ref(''); </script>
这样,子组件中的两个输入框分别与父组件中的两个变量实现了双向绑定。
-
处理
v-model
修饰符:defineModel
还支持处理v-model
的修饰符,例如.trim
、.number
和.lazy
。在子组件中,可以通过解构defineModel
的返回值来获取修饰符,然后根据修饰符调整数据的处理方式。
实现原理
defineModel
实际上是在子组件内定义了一个 ref
变量和对应的 modelValue
属性,并监听了对应的属性。当 props
中的 modelValue
的值改变后,会同步更新 ref
变量的值;当在子组件内改变 ref
变量的值后,会抛出 update:modelValue
事件,父组件收到这个事件后就会更新对应的变量值,从而实现双向绑定。
注意事项
defineModel
是一个宏,所以不需要从 Vue 中导入,直接使用即可。- 在 TypeScript 中使用
defineModel
时,可以提供类型推导支持,例如defineModel<string>()
。 defineModel
的返回值是一个ref
,在子组件中可以直接对这个ref
对象进行赋值,父组件内的相应变量也会同步修改。