簡介
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"><inputv-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"><inputv-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"><inputv-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"/><inputv-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"><MyComponentv-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 |
---|---|---|
代碼量 | 較多 | 簡潔 |
類型安全 | 需手動定義 | 自動推導 |
多模型支持 | 復雜 | 簡單 |
學習成本 | 較高 | 較低 |
性能 | 相同 | 相同 |
注意事項
- Vue 版本要求:需要 Vue 3.4+ 版本
- 編譯器支持:需要配置支持?
defineModel
?的編譯器 - 向后兼容:可以與傳統的 props/emits 方式混用
- SSR 支持:完全支持服務端渲染
總結
defineModel
?是 Vue 3.5+ 中一個強大而簡潔的 API,它大大簡化了組件雙向數據綁定的實現。通過減少樣板代碼、提供更好的類型支持和更直觀的 API,它讓開發者能夠更專注于業務邏輯的實現。
無論是簡單的表單輸入還是復雜的自定義組件,defineModel
?都能提供優雅的解決方案,是現代 Vue 開發中不可或缺的工具。
?Vue 3.5 defineModel:讓組件開發效率提升 10 倍 - 高質量源碼分享平臺-免費下載各類網站源碼與模板及前沿技術分享