Vue3 知识点记录(四):组件的 v-model

322 阅读1分钟

组件的 v-model

表单的 v-model

在开发中使用表单时,我们通常会使用v-model来进行数据的双向绑定。

<input v-model='message' />

v-model默认帮我们做了两件事:

  • value 属性进行数据绑定

  • input 事件进行监听

即,上面的代码相当于:

<input :value='message' @input='message = $event.target.value' />

组件的 v-model

v-model 属性也可以用在组件上。

什么情况下需要用到组件的 v-model 属性?

有些时候我们会把常用的表单控件封装成组件来使用,当我们在使用这些组件时肯定是希望像使用表单元素一样,实现双向数据绑定,这个时候就可以使用组件的 v-model 属性来实现。

组件上的 v-model 也默认帮我们做了两件事:

  • modelValue 属性进行数据绑定

  • update:modelValue 事件进行监听

<template>
   <div>
      <home v-model='message' />
      // 相当于
      <home :model-value='message' @update:model-value='message = $event' />
   </div>
</template>
import Home from '@/page/Home.vue'

export default {
  components:{
    Home,
  },
  data() {
    return {
      message: 'hello world'
    }
  }
}

home 组件中,我们需要

export default {
  props: ['modelValue'],
  emits: ['update:modelValue']
}

案例:我们封装了一个 my-input 组件,然后在父组件中使用 v-model 来对它进行数据的双向绑定:

<template>
   <div>
      <my-input v-model='message' />
      <!-- <my-input :model-value='message' @update:model-value='message = $event' /> -->
   </div>
</template>
import MyInput from '@/page/MyInput.vue'

export default {
  components:{
    MyInput,
  },
  data() {
    message: ''
  }
}

在子组件中:

// my-input 组件
<template>
   <div>
      <input :value='modelValue' @input='onInput' />
   </div>
</template>
export default {
  props: ['modelValue'],
  emits: ['update:modelValue'],
  methods: {
    onInput(e) {
      this.$emit('update:modelValue', e.target.value)
    }
  }
}

问题一:可不可以用 v-model 来替换上面 input 标签里的 :value='modelValue' @input='onInput'呢?

即:

<input v-model='modelValue' />

不可以。有两个原因:

  1. 如果写成 v-model 的形式,实际上相当于下面的代码:
<input :value='modelValue' @input='modelValue = $event.target.value' />  

这个时候不管怎么改变输入框的值,都只会修改 props 中的 modelValue ,而不会改变父组件中的值

  1. 在开发过程过中,一定不要直接来修改 props 中的数据

问题二:如果我们依然希望通过 v-model 的方式来实现的话,应该怎么做呢?这里我们用到计算属性 computed

<input v-model='finalValue' />
export default {
  props: ['modelValue'],
  emits: ['update:modelValue'],
  computed: {
    finalValue: {
      set(val) {
        this.$emit('update:modelValue', val)
      },
      get() {
        return this.modelValue
      }
    }
  }
}