
Vue 3 defineModel :告别繁琐的 v-model 绑定!
AI-摘要
KunKunYu GPT
AI初始化中...
介绍自己
生成本文简介
推荐相关文章
前往主页
前往tianli博客
什么是 defineModel
?
一句话定义:
defineModel
是 Vue 3.3 新增的宏(macro),用于在组件中快速声明一个可以与父组件通过v-model
双向绑定的模型。解决的问题:传统自定义
v-model
需要手动自定义props
和emit
,代码冗余核心优势:
减少样板代码(无需手动写
props
和emit
)。支持 TypeScript 类型推导。
兼容 Vue 2 的
v-model
行为(默认modelValue
)。
传统自定义 v-model
写法
父组件的写法
<template>
<div>
<h2>父组件</h2>
<p>父组件的值:{{ state }}</p>
<Child v-model="state" />
</div>
</template>
<script setup>
import { ref } from 'vue';
import Child from './Child.vue';
const state = ref(0);
</script>
子组件的写法
<template>
<div>
<h3>子组件</h3>
<input
type="text"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
<p>子组件的值:{{ modelValue }}</p>
</div>
</template>
<script setup>
import { defineProps, defineEmits } from 'vue';
const props = defineProps({
modelValue: String
});
const emit = defineEmits(['update:modelValue']);
</script>
defineModel 的写法
父组件的写法
<template>
<div>
<h2>父组件</h2>
<p>父组件的值:{{ state }}</p>
<Child v-model="state" />
</div>
</template>
<script setup>
import { ref } from 'vue';
import Child from './Child.vue';
const state = ref(0);
</script>
子组件的写法
<template>
<div>
<h3>子组件</h3>
<input
type="text"
:value="modelValue"
@input="(e) => (model = e.target.value)"
/>
<p>子组件的值:{{ modelValue }}</p>
</div>
</template>
<script setup>
import { defineModel } from 'vue';
const value = defineModel();
</script>
从子组件的对比写法来看,代码量减少了,并且导入依赖也变少了
defineModel 的扩展
内置修饰符
Vue 的 v-model
默认支持 .lazy
和 .trim
等修饰符,通过 defineModel
可以自动继承这些行为
<!-- 父组件 -->
<CustomInput v-model.trim="username" />
子组件无需额外处理,
defineModel
会自动将修饰符应用到模型值上
自定义修饰符
defineModel
允许通过 modifiers
选项声明自定义修饰符,并在逻辑中处理
eg:实现一个 .capitalize
修饰符(自动首字母大写)
<!-- 子组件 CapitalizedInput.vue -->
<script setup>
const model = defineModel({
// 声明支持的修饰符
modifiers: { capitalize: false }
})
watch(model, (value) => {
if (model.modifiers.capitalize) {
// 应用修饰符逻辑
model.value = value.charAt(0).toUpperCase() + value.slice(1)
}
})
</script>
<template>
<input v-model="model" />
</template>
父组件中应用
<template>
<!-- 应用自定义修饰符 -->
<CapitalizedInput v-model.capitalize="username" />
</template>
子组件通过
modifiers
选项声明可接受的修饰符。父组件通过
v-model.modifierName
传递修饰符。在子组件中通过
model.modifiers.modifierName
访问修饰符状态。
转换器:数据预处理
通过 defineModel
的 get
和 set
函数实现双向数据转换
eg: 将输入值转换为数字类型
<!-- 子组件 NumberInput.vue -->
<script setup>
const model = defineModel({
// 类型声明为 Number
type: Number,
// 转换器
get(value) {
// 从父组件接收的值(已确保是 Number)
return value
},
set(value) {
// 向父组件发送前,将字符串转为 Number
return Number(value)
}
})
</script>
<template>
<input
type="number"
:value="model"
@input="(e) => (model = e.target.value)"
>
</template>
注意事项
修饰符命名冲突:避免与 Vue 内置修饰符(如
.lazy
)重名。转换器性能:避免在
get
/set
中执行高开销计算(如复杂正则)。
文刊借鉴
文章内容有 ai 生成!
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 shiningHuang.cn
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果