defineModel
是 Vue 3.4+ 中引入的一个新特性,用于声明组件的 v-model
双向绑定的 prop
,并简化了父子组件之间的双向数据绑定过程。它允许在组件中创建双向绑定的 prop
,并自动处理 modelValue
和更新事件(update:modelValue
)。
为什么需要 defineModel
?
在 Vue 3 中,v-model
默认会绑定到 modelValue
属性,同时要求组件触发一个名为 update:modelValue
的事件来进行更新。这种写法虽然能够工作,但对于某些场景来说比较繁琐。
defineModel
的引入简化了这个过程,并允许你定义具有 v-model
功能的属性(不仅限于 modelValue
),并能够为该属性提供默认值、类型和其他选项。
语法
defineModel()
可以接受两个参数:
- 第一个参数:
string
或者不传递- 如果是字符串,它将用作
prop
名称(默认是modelValue
)。 - 如果没有传入参数,则默认使用
modelValue
。
- 如果是字符串,它将用作
- 第二个参数:对象选项
- 可以包含
type
、default
、required
等字段来为modelValue
提供更多的配置。
- 可以包含
示例 1:基础用法
父组件
<template>
<Counter v-model="count" />
</template>
<script setup>
import { ref } from 'vue';
import Counter from './Counter.vue';
const count = ref(0); // 父组件绑定的值
</script>
子组件
<script setup>
const count = defineModel();
</script>
<template>
<div>{{ count.value }}</div>
</template>
该组件会拥有一个 modelValue
属性,并且当值发生变化时,会触发 update:modelValue
事件。
示例 2:带有默认值和类型检查的 defineModel
父组件
<template>
<Counter v-model="count" />
</template>
<script setup>
import { ref } from 'vue';
import Counter from './Counter.vue';
const count = ref(0); // 父组件绑定的值
</script>
子组件
<script setup>
import { defineModel } from 'vue';
const modelValue = defineModel({
type: Number,
default: 0,
required: true,
});
function increment() {
modelValue.value++; // 直接修改值,自动触发 "update:modelValue" 事件
}
</script>
<template>
<div>
<button @click="increment">Increment</button>
<p>Value: {{ modelValue }}</p>
</div>
</template>
上面的代码定义了一个类型为 String
且默认值为 'Hello World'
的 modelValue
。
示例 3:多个 v-model
(使用自定义名称)
父组件
<template>
<Counter v-model:count="count" />
</template>
<script setup>
import { ref } from 'vue';
import Counter from './Counter.vue';
const count = ref(0); // 父组件绑定的值
</script>
子组件
<script setup>
const count = defineModel('count', { type: Number, default: 0 });
</script>
<template>
<div>{{ count.value }}</div>
</template>
通过传入字符串 'count'
,组件会使用 v-model:count
来进行双向绑定。
defineModel
的实用场景
defineModel
在需要处理多个双向绑定的 prop
时特别有用。例如,某些组件可能需要处理多个属性的双向绑定,你可以为每个属性创建一个 defineModel
来替代手动管理 v-model
和事件的繁琐步骤。
特别注意
v-model
的修饰符:如果你使用了v-model.trim
、v-model.lazy
等修饰符,你可以通过defineModel
的选项来处理这些修饰符,并对modelValue
的值进行转换(例如去除空格、延迟更新等)。- 双向绑定的限制:
defineModel
仅用于声明父子组件之间的双向绑定,但父组件必须通过v-model
绑定值,子组件则使用defineModel
来接收这个值并更新它。
修饰符和转换器
为了获取 v-model
指令使用的修饰符,我们可以像这样解构 defineModel()
的返回值:
const [modelValue, modelModifiers] = defineModel()
// 对应 v-model.trim
if (modelModifiers.trim) {
// ...
}
当存在修饰符时,我们可能需要在读取或将其同步回父组件时对其值进行转换。我们可以通过使用 get
和 set
转换器选项来实现这一点:
const [modelValue, modelModifiers] = defineModel({
// get() 省略了,因为这里不需要它
set(value) {
// 如果使用了 .trim 修饰符,则返回裁剪过后的值
if (modelModifiers.trim) {
return value.trim()
}
// 否则,原样返回
return value
}
})
总结
defineModel
的主要作用是简化 Vue 3 组件的 v-model
使用,它让你能够更轻松地管理组件的双向绑定,自动处理 modelValue
和 update:modelValue
,并允许自定义绑定名称和提供类型、默认值等选项。
通过 defineModel
,你可以让父子组件之间的双向数据绑定变得更加简洁和高效。
暂无评论内容