v-module 双向绑定, 以及 VUE3.4 新语法 defineModel 的前世今生

500 阅读2分钟

组件v-model: 组件 v-model

defineModel宏: definemodel

vue中提供的 v-model 可以在表单标签(<input>等 )上使用以实现双向绑定

同样的, 在自定义组件中也可使用 v-model实现双向绑定, 但子组件需要做对应的处理才可以

随着vue3.4的发布, 现在可以使用defineModel简化双向绑定的写法

v-module语法糖

我们知道VUE是单向数据流, v-model指令的双向绑定实际是一个语法糖

<input v-model="text" />
<!-- 等价于 -->
<input :value="text" @input="event => text = event.target.value" />

另外,v-model 还可以用于各种不同类型的输入,、 元素。它会根据所使用的元素自动使用对应的 DOM 属性和事件组合

组件的v-module

VUE3.4 之前, 为了实现组件的v-module需要在子组件自己处理prop和事件, 有时候为了在子组件更方便的使用父组件双向绑定的属性, 还要加上一个计算属性:

<!-- 父组件 -->
<ComponentDemo v-model="name"></ComponentDemo><!-- 子组件 -->
<script setup>
  import { computed } from 'vue'
  const props = defineProps(['modelValue'])
  const emits = defineEmits(['update:modelValue'])
  const name = computed({
    get() {
      return props.modelValue
    },
    set(newVal) {
      emits('update:modelValue', newVal)
    }
  })
</script>

defineModel

VUE3.4为我们提供了新的definemodel宏, 如果使用defineModel, 那一行js代码就可以实现上面的功能

<script setup>
  const name = defineModel()
</script>
  • defineModel 是一个便利宏, 源码中是使用 customRefwatchSyncEffect实现的

  • 使用defineModel先决条件

    • <script setup>
    • vue3.4+

defineModel 的更多语法

双向绑定多个属性时可以指定参数名

<!-- 父组件 -->
<ComponentDemo v-model:age="age" v-model:isActive="isActive"></ComponentDemo><!-- 子组件 -->
<script setup>
  const age = defineModel('age')
  const isActive = defineModel('isActive')
</script>

约束prop参数可以在 model 名称之后传递额外的 prop 选项

<!-- 父组件 -->
<ComponentDemo v-model:isActive="isActive"></ComponentDemo><!-- 子组件 -->
<script setup>
  const isActive = defineModel('isActive', { required: false, type: Boolean, default: false })
</script>

处理 v-model 修饰符

当存在修饰符时,我们可能需要在读取或将其同步回父组件时对其值进行转换。我们可以通过使用 get 和 set 转换器选项来实现这一点

<!-- 父组件 -->
<ComponentDemo v-model="name"></ComponentDemo><!-- 子组件 -->
<script setup>
  const [name, modifiers] = defineModel('name', {
    required: true,
    type: String,
    // 配合修饰符使用
    set: (val) => {
      let newVal = val
      if (modifiers.toLowerCase) {
        newVal = newVal.toLowerCase()
      }
      if (modifiers.capitalize) {
        newVal = newVal.charAt(0).toUpperCase() + newVal.slice(1)
      }
      return newVal
    }
  })
</script>

总结

本文介绍了v-module 双向绑定的原理, 以及如何在组价上使用双向绑定 相比于之前的语法, defineModel大大简化了自定义组件数据通信的代码 如果项目使用 Vue 3.4+ , 更推荐使用defineModel宏实现自定义组件双向绑定