Vue3$Data-V-Model
0. What is v-model
对于 input 和 select 等 form 组件,我们希望数据能够双向绑定:初始值决定 value,同时页面上 value 的改变引起数据。
和 input 类似,传给组件的值也可以双向绑定。
我们知道 props 是单向数据流,为的是子组件不更改父组件的数据。而 v-model 是双向绑定,“双向数据流”,好像是破坏了 props 的美好设想:数据的更改操作可以在多个地方(父子组件)。
还是以抄作业为例。父组件把作业给子组件抄:
- 多数情况下我们不希望子组件修改我们的答案,你不想这些“差生”改你的答案
- 一些情况,你希望子组件修改你的答案,比如有道题你没做,或者只写了解题思路。你想让那个“好学生”来做
从组件本身来考虑:
- 子组件如果只是想用外部数据,使用 props 就好
- 子组件如果想帮父组件做点事(修改数据),使用 v-model
v-model 其实是语法糖。它使用了 props 来接收数据,同时当数据更改时 emit 了更新事件。
<!-- Child.vue -->
<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>
<!-- Parent.vue -->
<Child
:modelValue="foo"
@update:modelValue="$event => (foo = $event)"
/>
1. How to Use v-model
基本使用
<!-- Child.vue -->
<script setup>
const model = defineModel()
function update() {
model.value++
}
</script>
<template>
<div>Parent bound v-model is: {{ model }}</div>
<button @click="update">increase</button>
</template>
<!-- Parent.vue -->
<Child v-model="modelCount" />
参数(用于区分多个数据)
<MyComponent v-model:title="bookTitle" v-model:name="Tom" />
<!-- MyComponent.vue -->
<script setup>
const title = defineModel('title')
// const title = defineModel('title', { required: true })
const name = defineModel('name)
</script>
<template>
<input type="text" v-model="title" />
<input type="text" v-model="name" />
</template>
限制 Options
// making the v-model required
const model = defineModel({ required: true })
// providing a default value
const model = defineModel({ default: 0 })
修饰符
- 普通 form 修饰符:
.trim,.nnumber,.lazy - 组件自定义修饰符
<MyComponent v-model.capitalize="myText" />
<script setup>
const [model, modifiers] = defineModel()
console.log(modifiers) // { capitalize: true }
</script>
<template>
<input type="text" v-model="model" />
</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>