前言:

在 Vue 3.4 版本中,官方引入了 defineModel 宏,以简化组件之间的双向数据绑定。在此之前,开发者通常需要手动定义 modelValue 属性,并通过 update:modelValue 事件来实现双向绑定,这在某些情况下可能显得繁琐。

一、传统的双向绑定方式

在 Vue 3.4 之前,实现双向绑定通常需要在子组件中定义 modelValue 属性,并在需要更新时触发 update:modelValue 事件。例如:

<!-- 子组件 -->
<template>
  <input
    :value="modelValue"
    @input="handleInput"
  />
</template>

<script setup>
const props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);

function handleInput(event) {
  emit('update:modelValue', event.target.value);
}
</script>

在父组件中,使用时需要绑定 modelValue 并监听 update:modelValue 事件:

<!-- 父组件 -->
<template>
  <ChildComponent
    :modelValue="value"
    @update:modelValue="newValue => value = newValue"
  />
</template>

<script setup>
import { ref } from 'vue';

const value = ref('');
</script>

二、使用 defineModel 简化双向绑定:

从 Vue 3.4 开始,defineModel 宏提供了一种更简洁的方式来实现双向绑定。它返回一个 ref,可以直接在模板中使用 v-model 进行绑定。

在子组件中,使用 defineModel 定义模型:

<!-- 子组件 -->
<template>
  <input v-model="model" />
</template>

<script setup>
const model = defineModel();
</script>

在父组件中,使用 v-model 进行绑定:

<!-- 父组件 -->
<template>
  <ChildComponent v-model="value" />
</template>

<script setup>
import { ref } from 'vue';

const value = ref('');
</script>

通过 defineModel,Vue 会自动处理 modelValue 属性和 update:modelValue 事件的定义,使代码更加简洁。需要注意的是,defineModel 返回的 ref 需要在子组件中使用 v-model 进行绑定。

三、处理 v-model 修饰符:

defineModel 还支持处理 v-model 的修饰符,例如 .trim.number.lazy。在子组件中,可以通过解构 defineModel 的返回值来获取修饰符:

<!-- 子组件 -->
<template>
  <input v-model="model" />
</template>

<script setup>
const [model, modifiers] = defineModel();

if (modifiers.trim) {
  // 处理 trim 修饰符
}
</script>

通过这种方式,子组件可以根据父组件传递的修饰符来调整数据的处理方式。

四、多个 v-model 绑定:

defineModel 还支持多个 v-model 绑定。在子组件中,可以为每个模型定义一个 ref

<!-- 子组件 -->
<template>
  <input v-model="firstName" />
  <input v-model="lastName" />
</template>

<script setup>
const firstName = defineModel('firstName');
const lastName = defineModel('lastName');
</script>

在父组件中,使用多个 v-model 进行绑定:

<!-- 父组件 -->
<template>
  <ChildComponent
    v-model:first-name="firstName"
    v-model:last-name="lastName"
  />
</template>

<script setup>
import { ref } from 'vue';

const firstName = ref('');
const lastName = ref('');
</script>

通过 defineModel,可以方便地在子组件中处理多个双向绑定,提升代码的可维护性和可读性。

五、在 TypeScript 中使用 defineModel

defineModel 也可以与 TypeScript 一起使用,以提供类型推导支持:

<!-- 子组件 -->
<template>
  <input v-model="model" />
</template>

<script setup lang="ts">
const model = defineModel<string>();
</script>

 六、自定义 getset 方法

defineModel 允许传入包含 getset 方法的对象,以自定义模型的读取和写入行为:

<!-- 子组件 -->
<template>
  <input v-model="model" />
</template>

<script setup>
const model = defineModel({
  get() {
    // 自定义读取行为
  },
  set(value) {
    // 自定义写入行为
  }
});
</script>

通过这种方式,子组件可以精确控制模型的处理逻辑。

总结:

defineModel 是 Vue 3.4 引入的一个重要特性,旨在简化组件之间的双向数据绑定。通过使用 defineModel,开发者可以更方便地处理 v-model,使代码更加简洁和易于维护。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐