v-model
是 Vue 应用中最常用的指令。它通常用于在表单元素上创建双向数据绑定,并与 input
、checkbox
、select
、textarea
和 radio
表单元素一起使用。
在下面的例子中,v-model
应用于 input
元素,将 someVal
变量与 input
的原生 value
属性绑定在一起。
<input v-model="someVal" />
v-model
本质上是一种语法糖,通过在内部为不同类型的 input
元素使用不同的属性并抛出不同的事件。
上面的示例中,指令会监听原生的 input
事件,并在每次触发时更新 someVal
。
因此,我们可以将上述代码重写为具有相同效果的事件和属性:
<input :value="someVal" @input="someVal = $event.target.value" />
不难看出,单向绑定 + 事件便可达到双向绑定的效果。
这就是 v-model
应用于常规输入的工作原理。
其他的表单元素如下:
input
元素若是text / textarea
类型,使用value
属性和input
事件。input
元素若是radio / checkbox
类型,使用checked
属性和change
事件。select
元素使用value
属性和change
事件。
要在组件上使用 v-model
指令实现双向绑定,我们可以在每个会发出 update:modelValue
事件并接受 modelValue
值的组件上使用 v-model
。
注意:Vue 2.x 使用
value
属性和input
事件。
以下是一个 myCounter
组件:
<template>
<button @click="changeValue(modelValue - 1)">-</button>
<span>{{ modelValue }}</span>
<button @click="changeValue(modelValue + 1)">+</button>
</template>
<script setup>
defineProps({
modelValue: Number
})
const emit = defineEmits(['update:modelValue'])
const changeValue = (newVal) => {
console.log(newVal)
emit('update:modelValue', newVal)
}
</script>
由于每次更改 update:modelValue
事件时都会发出一个新值,并接受 modelValue
属性,因此我们可以安全地在此组件上使用 v-model
指令:
<myCounter v-model="count" />
<!-- 相当于 -->
<custom-input
:modelValue="searchText"
@update:modelValue="searchText = $event"
></custom-input>
v-model
还支持通过参数来修改默认名称:
<template>
<!-- v-model 参数 -->
<custom-input v-model:title="pageTitle"></custom-input>
<!-- 相同于 -->
<!-- <custom-input :title="pageTitle" @update:title="pageTitle = $event" /> -->
<p>Title: {{ pageTitle }}</p>
</template>
<script setup lang="ts">
import CustomInput from './CustomInput.vue'
import { ref } from 'vue'
const pageTitle = ref('Vue')
</script>
<!-- CustomInput -->
<template>
<input :value="title" @input="$emit('update:title', $event.target.value)" />
</template>
<script setup>
defineProps({
title: String
})
</script>
Vue 3 允许我们在同一组件上绑定多个 v-model
:
<template>
<custom-input v-model:title="pageTitle" v-model:content="pageContent" />
<!-- 相同于 -->
<!-- <custom-input
:title="pageTitle"
@update:title="pageTitle = $event"
:content="pageContent"
@update:content="pageContent = $event"
/> -->
<p>Value: {{ pageTitle }}</p>
<p>content: {{ pageContent }}</p>
</template>
<script setup>
import CustomInput from './component/CustomInput.vue'
import { ref } from 'vue'
const pageTitle = ref('admin')
const pageContent = ref('Element')
</script>
<!-- CustomInput -->
<template>
<input :value="title" @input="$emit('update:title', $event.target.value)" />
<input
:value="content"
@input="$emit('update:content', $event.target.value)"
/>
</template>
<script setup>
defineProps({
title: String,
content: String
})
</script>
v-model
支持的三个修饰符:
.lazy
— 默认情况下,v-model
监听input
事件,这意味着每次输入值都会同步更新数据。.lazy
修饰符将事件监听改为change
事件,也就是失焦时同步更新数据。这减少了 Vue 实例同步次数,并且在某些情况下,可以显著提高性能。.number
— 将有效输入字符串强制转换为数字。.trim
— 修剪输入,想一下 JS 字符串的trim()
方法。
<input type="text" v-model.trim.lazy="value" />
你可以自由的链接多个修饰符以达到目的。
Vue 3 还有一些其他的更改,如 .sync
修饰符被合并到了 v-model
中、自定义 v-model
修饰符。
Vue 允许我们自定义 v-model
修饰符。
以下是官网的一个示例:
<custom-input v-model.capitalize="text" />
<script setup>
import { ref } from 'vue'
const text = ref('')
</script>
<input type="text" :value="modelValue" @input="emitValue" />
<script setup>
const props = defineProps({
modelValue: String,
modelModifiers: { default: () => ({}) } // <- 关键
})
const emit = defineEmits(['update:modelValue'])
const emitValue = (e) => {
let value = e.target.value
if (props.modelModifiers.capitalize) {
value = value.charAt(0).toUpperCase() + value.slice(1)
}
emit('update:modelValue', value)
}
</script>
组件的 v-model
上所添加的修饰符,可以通过 modelModifiers
prop 在组件内访问到。
更多详细内容请看官网(实时更新)。