defineModel
2024年03月13日
一、认识
defineModel
可以用来声明一个双向绑定 prop
,通过父组件的 v-model
来使用。defineModel()
返回的值是一个 ref
。它可以像其他 ref
一样被访问以及修改, 能起到在父组件和当前变量之间的双向绑定的作用。
-
它的
.value
和父组件的v-model
的值同步 -
当它被子组件变更了,会触发父组件绑定的值一起更新
defineModel
是一个便利宏。编译器将其展开为以下内容:
-
一个名为
modelValue
的prop
,本地ref
的值与其同步 -
一个名为
update:modelValue
的事件,当本地ref
的值发生变更时触发
defineModel
底层机制如下:
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>
<template>
<input
:value="props.modelValue"
@input="emit('update:modelValue', $event.target.value)"
/>
</template>
二、语法
2.1 modelValue
// 第一个参数不传, 默认 prop 名称为 modelValue
const model = defineModel()
// 第一个参数为对象, 默认 prop 名称为 modelValue, 且传入配置
const model = defineModel({ type: String, default: "xx", require: true })
// 第一个参数如果为字符串变量,用作 prop 名称为 xx
const model = defineModel("xx")
// 第一个参数如果为字符串变量, 用作 prop 名称为 xx, 且传入配置
const model = defineModel("xx",{ type: String, default: "xx", require: true })
2.2 modelModifiers
为了获取 v-model
指令使用的修饰符,我们可以像这样解构 defineModel()
的返回值
const [modelValue, modelModifiers] = defineModel()
// 对应 v-model.trim
if (modelModifiers.trim) {
// ...
}
三、用法
3.1 使用 modelValue
子组件展示、修改
// 父组件
<Child v-model="count"></Child>
// 子组件
<script setup>
const model = defineModel({ default: 0, require: true})
function update() {
model.value++
}
</script>
<template>
<div>parent bound v-model is: {{ model }}</div>
</template>
子组件双向绑定
// 父组件
<Child v-model="count"></Child>
// 子组件
<script setup>
const model = defineModel({ default: 0, require: true})
</script>
<template>
<span>My input</span> <input v-model="model">
</template>
父组件使用多个 v-model
// 父组件
<script setup>
import { ref } from 'vue'
import UserName from './UserName.vue'
const first = ref('John')
const last = ref('Doe')
</script>
<template>
<h1>{{ first }} {{ last }}</h1>
<UserName
v-model:first-name="first"
v-model:last-name="last"
/>
</template>
// 子组件
<script setup>
const firstName = defineModel('firstName')
const lastName = defineModel('lastName')
</script>
<template>
<input type="text" v-model="firstName" />
<input type="text" v-model="lastName" />
</template>
3.2 使用 modelModifiers
v-model.trim
// 父组件
<script setup>
import { ref } from 'vue'
import MyComponent from './MyComponent.vue'
const myText = ref('')
</script>
<template>
This input capitalizes everything you enter:
<MyComponent v-model.trim="myText" />
</template>
// 子组件
<script setup>
const [modelValue, modelModifiers] = defineModel({
set(value) {
if (modelModifiers.trim) {
return value.trim()
}
return value
}
})
</script>
<template>
<input type="text" v-model="modelValue" />
</template>
v-model.capitalize
// 父组件
<script setup>
import { ref } from 'vue'
import MyComponent from './MyComponent.vue'
const myText = ref('')
</script>
<template>
This input capitalizes everything you enter:
<MyComponent v-model.capitalize="myText" />
</template>
// 子组件
<script setup>
const [model, modifiers] = defineModel({
set(value) {
if (modifiers.capitalize) {
return value.charAt(0).toUpperCase() + value.slice(1)
}
return value
}
})
</script>
<template>
<input type="text" v-model="model" />
</template>