vue3中自定义组件,实现数据双向绑定

13,693 阅读1分钟

原生组件使用v-model

vue中,v-model指令可以实现表单<input><textarea><select>等元素的双向数据绑定。v-model本质上是语法糖,为不同的表单元素使用不同的属性值并抛出不同的事件。如下代码,v-model为input元素绑定了value属性和input事件。

<input v-model="searchText" />

等价于

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

vue3自定义组件使用v-model

v-model指令

在自定义组件上使用v-model指令时,会给组件绑定一个model-value属性和一个update:model-value监听事件。

<custom-input v-model="searchText"></custom-input>

等价于

<custom-input
  :model-value="searchText"
  @update:model-value="searchText = $event"
></custom-input>

自定义组件内部会接收一个名为modelValue的props,和一个名为update:modelValue的emits。自定义组件将新值,通过emit(update:modelValue, value)将事件抛出,从而实现数据的双向绑定。

app.component('custom-input', {
  props: ['modelValue'],
  emits: ['update:modelValue'],
  template: `
    <input
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"
    >
  `
})

v-model参数

v-model也可以接收一个参数,改变绑定的名称,如下代码,自定义组件,将接收一个名称为title的props和一个update:title的监听事件,自定义组件通过emit(update:title, value)抛出事件。

<ChildComponent v-model:title="pageTitle" />

<!-- 是以下的简写: -->

<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />

在自定义组件上使用多个v-model

可以给自定义组件设置多个v-model,下面代码中,组件有两个名为title和content的v-model。组件将接收titlecontent两个props,update:titleupdate:content两个emits,自定义组件通过emit(update:title)emit(update:content)抛出事件。

<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />

<!-- 是以下的简写: -->

<ChildComponent
  :title="pageTitle"
  @update:title="pageTitle = $event"
  :content="pageContent"
  @update:content="pageContent = $event"
/>

举例说明

实现一个自定义组件,输入的小写字母自动转换成大写字母。

//使用自定义组件
<my-input v-model="myInputvalue"/>
{{myInputvalue}}
// MyInput.vue
<template>
  <input :value="inputVal" @input="updateValue"/>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'

export default defineComponent({
  props: ['modelValue'],
  emits: ['update:modelValue'],
  setup (props, context) {
    const inputVal = ref(props.modelValue.toUpperCase())
    const updateValue = (e: KeyboardEvent) => {
      const targetValue = (e.target as HTMLInputElement).value.toUpperCase()
      inputVal.value = targetValue
      context.emit('update:modelValue', targetValue)
    }
    return {
      inputVal,
      updateValue
    }
  }
})
</script>