【vue3 自定义组件中使用v-model实现双向绑定】


前言

比如我们有自定义的Form组件、Input组件。

如果Form组件想拿到Input组件中input框输入的内容,我们可以让Form这个父组件给Input子组件传值props:value(不能直接修改子组件的props),子组件定义变量记录prop的值,子组件监听数据变化,再用$emit('input')传给父组件,父组件接收调用方法去修改value。

vue3可以使用组件v-model去解决上述问题,从而实现组件的双向数据绑定。v-model是$emit('input')props:value的语法糖。

使用组件 v-model 的主要好处是无需记特定的 prop 字段名,即可绑定到组件中的值,降低组件的使用成本。

简单封装Input组件

Input.vue

<template>
  <div>
    <input type="text"
           :value="inputRef.val"
            @input="updateValue"
    >
  </div>
</template>
// ......
props:{
    
    
  modelValue: String // 默认使用 modelValue 作为prop
},
setup(props, context) {
    
    
	const inputRef = reactive({
    
    
      val: props.modelValue || '', // 不建议直接修改props中的数据
      error: false,
      message: ''
    })
	const updateValue = (e: KeyboardEvent) => {
    
    
      const targetValue = (e.target as HTMLInputElement).value
      inputRef.val = targetValue // 拿到更新后的值
      context.emit('update:modelValue', targetValue) // emit传递的方法名必须是update:modelValue
    }
}

在组件中使用Input组件
Form.vue

<template>
    <form>
     <Input v-model="emailVal"/>
    </form>
</template>
// 
<script lang="ts">
import {
    
     defineComponent, reactive, ref } from 'vue'
// ....
export default defineComponent({
    
    
  name: 'Form.vue',
  components: {
    
    
   Input 
  },
  setup () {
    
    
    const emailVal = ref('')
    return {
    
    
      emailVal
    }
  }
})
</script>

<Input v-model="emailVal"/> 在代码背后,模板编译器会对 v-model 进行更冗长的等价展开。因此上面的代码其实等价于下面这段:


<Input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)"/

v-mode参数

使用Input组件<Input v-model="emailVal"/>时,input组件默认使用 modelValue 作为prop。
当然也可以自定义<Input v-model:emailVal="emailVal"/>,input组件中就可以使用emailVal作为prop:

props:{
    
    
  emailVal: String // 默认使用 modelValue 作为prop
},

多个v-model绑定

此外,也可以有多个v-model绑定,如:

<UserName
  v-model:first-name="first"
  v-model:last-name="last"
/>

子组件编写方式:

<script setup>
defineProps({
    
    
  firstName: String,
  lastName: String
})

defineEmits(['update:firstName', 'update:lastName'])
</script>

<template>
  <input
    type="text"
    :value="firstName"
    @input="$emit('update:firstName', $event.target.value)"
  />
  <input
    type="text"
    :value="lastName"
    @input="$emit('update:lastName', $event.target.value)"
  />
</template>

更多内容详见官方文档Vue官网-组件 v-model

猜你喜欢

转载自blog.csdn.net/weixin_42936434/article/details/131869562