所有分类
  • 所有分类
  • Html5资源
  • React资源
  • Vue资源
  • Php资源
  • ‌小程序资源
  • Python资源

Vue 3.5 defineModel:让组件开发效率提升 10 倍

简介

defineModel 是 Vue 3.4 引入并在 Vue 3.5+ 中稳定的一个组合式 API,它简化了组件的双向数据绑定实现。在此之前,实现双向绑定需要手动定义 props 和 emits,而 defineModel 将这个过程自动化,让代码更加简洁和直观。

主要特性

  • 简化双向绑定:自动处理 props 和 emits 的定义
  • 类型安全:完整的 TypeScript 支持
  • 多模型支持:支持多个 v-model 绑定
  • 向后兼容:与现有的 props/emits 模式完全兼容

基础用法

传统方式 vs defineModel

传统方式(Vue 3.4 之前):

<script setup>
// 子组件
const props = defineProps(["modelValue"]);
const emit = defineEmits(["update:modelValue"]);

const updateValue = (newValue) => {
  emit("update:modelValue", newValue);
};
</script>

<template>
  <input :value="props.modelValue" @input="updateValue($event.target.value)" />
</template>

使用 defineModel:

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

<template>
  <input v-model="model" />
</template>

父组件使用

<script setup>
import { ref } from "vue";
import MyInput from "./MyInput.vue";

const inputValue = ref("Hello World");
</script>

<template>
  <MyInput v-model="inputValue" />
  <p>当前值:{{ inputValue }}</p>
</template>

高级用法

综合示例

<!-- 子组件 -->
<script setup>
// 定义 v-model
const modelValue = defineModel();

// 带默认值
const count = defineModel("count", { default: 0 });

// 多个 v-model
const firstName = defineModel("firstName");
const lastName = defineModel("lastName");
</script>

<template>
  <div class="min-h-screen bg-gray-100 py-8 px-4">
    <div class="max-w-lg mx-auto">
      <div class="bg-white rounded-lg shadow-md p-6">
        <h2 class="text-xl font-semibold text-gray-800 mb-6 text-center">
          用户信息表单
        </h2>

        <div class="space-y-4">
          <!-- Main Value Input -->
          <div>
            <label class="block text-sm font-medium text-gray-700 mb-2">
              主要信息
            </label>
            <div class="flex items-center space-x-3">
              <input
                v-model="modelValue"
                placeholder="请输入主要信息"
                class="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-gray-500 focus:border-gray-500 transition-colors"
              />
              <span class="text-sm text-gray-600 min-w-0 flex-shrink-0">
                {{ modelValue || "未填写" }}
              </span>
            </div>
          </div>

          <!-- Count Input -->
          <div>
            <label class="block text-sm font-medium text-gray-700 mb-2">
              数量
            </label>
            <div class="flex items-center space-x-3">
              <input
                v-model="count"
                type="number"
                placeholder="请输入数量"
                class="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-gray-500 focus:border-gray-500 transition-colors"
              />
              <span class="text-sm text-gray-600 min-w-0 flex-shrink-0">
                {{ count }}
              </span>
            </div>
          </div>

          <!-- Name Inputs -->
          <div>
            <label class="block text-sm font-medium text-gray-700 mb-2">
              姓名
            </label>
            <div class="grid grid-cols-2 gap-3 mb-2">
              <input
                v-model="firstName"
                placeholder="名字"
                class="px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-gray-500 focus:border-gray-500 transition-colors"
              />
              <input
                v-model="lastName"
                placeholder="姓氏"
                class="px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-gray-500 focus:border-gray-500 transition-colors"
              />
            </div>
            <div class="text-right">
              <span class="text-sm text-gray-600">
                {{
                  firstName && lastName
                    ? `${firstName} ${lastName}`
                    : "未完整填写"
                }}
              </span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<!-- 父组件 -->
<script setup>
import { ref } from "vue";
import MyComponent from "./MyComponent.vue";

const value = ref("Hello");
const count = ref(5);
const first = ref("John");
const last = ref("Doe");
</script>

<template>
  <div class="min-h-screen bg-gray-50">
    <MyComponent
      v-model="value"
      v-model:count="count"
      v-model:firstName="first"
      v-model:lastName="last"
    />
  </div>
</template>

验证器

const count = defineModel("count", {
  default: 0,
  validator: (value) => {
    return typeof value === "number" && value >= 0;
  },
});

修饰符 (.trim, .lazy)

const text = defineModel("text", {
  default: "",
  // 使用 set 转换器自动去除空格
  set(value) {
    return typeof value === "string" ? value.trim() : value;
  },
});

与传统方式的对比

特性传统方式defineModel
代码量较多简洁
类型安全需手动定义自动推导
多模型支持复杂简单
学习成本较高较低
性能相同相同

注意事项

  1. Vue 版本要求:需要 Vue 3.4+ 版本
  2. 编译器支持:需要配置支持 defineModel 的编译器
  3. 向后兼容:可以与传统的 props/emits 方式混用
  4. SSR 支持:完全支持服务端渲染

总结

defineModel 是 Vue 3.5+ 中一个强大而简洁的 API,它大大简化了组件双向数据绑定的实现。通过减少样板代码、提供更好的类型支持和更直观的 API,它让开发者能够更专注于业务逻辑的实现。

无论是简单的表单输入还是复杂的自定义组件,defineModel 都能提供优雅的解决方案,是现代 Vue 开发中不可或缺的工具。

资源下载
下载价格免费
注意:本网站资源属于虚拟产品,不支持退款。请谨慎购买! 购买后资源无法下载,请联系客服QQ:844475003,微信号:th844475003。
原文链接:https://code.ifrontend.net/archives/918,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?