Vue3-在组件上使用v-model

1,580 阅读1分钟

组件上使用v-model

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

由于props是单向数据流,子组件修改props的值是不会同步到父组件去的。如果我们想要实现子组件和父组件数据双向绑定,可以在组件上使用v-model

v-model本质上是一个语法糖:

<input v-model="searchText" />

和下面这段代码是等价的:

<input
  :value="searchText"
  @input="searchText = $event.target.value"
/>

​ 将v-mode的属性绑定给input元素的value属性,然后去监听输入事件,当事件触发去获取传入的值,然后将值赋值给v-mode的属性。这样就完成了双向绑定。

当作用在一个组件上时,v-model 是这样做的:

(原理一样,绑定属性然后去监听事件,当事件触发去获取事件传入的值,去赋值给绑定的属性)

<CustomInput
  :modelValue="searchText"
  @update:modelValue="newValue => searchText = newValue"
/>

​ 默认情况下,v-model 在组件上都是使用 modelValue 作为 prop的属性名称,以 update:modelValue 作为对应的事件名次。

实现在组件上使用v-model的步骤:

  1. 定义一个名为modelValue的props属性。
  2. 定义一个名为 update:modelValue 的自定义事件。
  3. 创建一个input标签,将modelValue绑定给input的value属性。
  4. 监听input标签的输入事件,当事件触发,则抛出自定义事件。

代码实现:

//hello-world组件中
//定义props
defineProps<{
   modelValue: string
}>()
//定义自定义事件
const emits = defineEmits<{
   (e: "update:modelValue", str: string): void
}>();

//监听input的输入事件
function input(event: Event) {
   //抛出自定义事件。
   emits("update:modelValue", (event.target as HTMLInputElement).value)
}
<!--绑定props和监听输入事件-->
<input :value="modelValue" @input="input($event)">

父组件:

<hello-world v-model="reactive1.name"></hello-world>

组件上绑定多个v-model

一个组件上是可以绑定多个v-model的,在前面有提到过,v-model作用在组件上,默认绑定的属性是modelValue,监听的事件是update:modelValue。但其实v-model绑定的值是可以指定的。

指定v-model绑定的属性:

HelloWorld 组件内:

defineProps<{
   personName: string
}>()

const emits = defineEmits<{
   (e: "update:personName", str: string): void
}>();

function inputEvent(event: Event) {
   emits("update:personName", (event.target as HTMLInputElement).value)
}

<input :value="personName" @input="inputEvent($event)">

在父组件中使用:

<hello-world v-model:person-name="person.name"></hello-world>

​ 通过v-model:属性名称的方式来指定绑定的属性,如果指定了属性,则监听的事件也会自动变化,监听的事件会变成update:属性名称的形式。

能够指定v-model绑定的属性,那么就可以实现在一个组件上绑定多个v-model

子组件内:

<script setup lang="ts">
defineProps<{
   personName: string,
   sex: string
}>()

const emits = defineEmits<{
   (e: "update:personName", str: string): void
   (e: "update:sex", str: string): void
}>();

function inputEvent(event: Event) {
   emits("update:personName", (event.target as HTMLInputElement).value)
}
function inputEvent2(event: Event) {
   emits("update:sex", (event.target as HTMLInputElement).value)
}
</script>

<template>
   <input :value="personName" @input="inputEvent($event)">
   <input :value="sex" @input="inputEvent2($event)">
</template>

父组件使用:

<hello-world v-model:person-name="person.name" v-model:sex="person.sex"></hello-world>