本文详解 Vue 3 中自定义 组件支持 v-model 的实现原理与完整方案,包括 modelValue props、update:modelValue 事件触发、双向绑定适配及密码切换等细节,确保默认值正确渲染且数据实时同步。
本文详解 vue 3 中自定义 `
Vue 的 v-model 在自定义组件中并非“开箱即用”,它本质是语法糖:v-model="value" 等价于 :modelValue="value" @update:modelValue="newValue => value = newValue"。因此,要使你的
✅ 正确实现 v-model 的关键步骤
- 接收 modelValue 作为 prop(取代 inputValue 的初始 data)
- 通过 $emit('update:modelValue', newValue) 同步更新父级数据
- 将 v-model 绑定到内部 的 :value 和 @input(或 @change/@blur),而非 v-model(避免递归)
- 移除本地 data() 中的 inputValue,改用 props.modelValue 作为显示值
以下是修复后的完整组件代码(适配 Vue 3 Composition API 风格,兼容 Options API):
<template><div class="position-relative">
<input :class="[{ 'pe-5': type === 'password' }, 'form-control p-2 rounded-3']" :type="inputType" :id="label ? slugify(label) : null" :value="modelValue" v-model>
@input="$emit('update:modelValue', $event.target.value)" <!-- 触发更新 -->
v-bind="$attrs"
/>
<custombutton v-if="type === 'password'" type="button" transparent class="position-absolute end-0 top-50 translate-y--50"><remixicon :icon="showPassword ? 'eye-off-line' : 'eye-line'"></remixicon></custombutton>
</div>
</template><script>
import RemixIcon from '../components/RemixIcon.vue';
import CustomButton from '../components/CustomButton.vue';
export default {
name: 'TextInput',
components: { RemixIcon, CustomButton },
props: {
type: {
type: String,
default: 'text'
},
label: {
type: String,
default: ''
},
modelValue: { // ? 关键:接收 v-model 绑定的值
type: [String, Number], // 支持字符串和数字类型
default: ''
}
},
emits: ['update:modelValue'], // ? 显式声明事件(Vue 3 推荐)
data() {
return {
showPassword: false
};
},
computed: {
inputType() {
return this.showPassword ? 'text' : this.type;
}
},
methods: {
togglePasswordVisibility() {
this.showPassword = !this.showPassword;
},
slugify(str) {
return str
.toLowerCase()
.trim()
.replace(/[^\w\s-]/g, '')
.replace(/[\s_-]+/g, '-')
.replace(/^-+|-+$/g, '');
}
}
};
</script>
✅ 使用方式(完全兼容原写法)
<!-- 父组件 -->
<template><textinput type="text" v-model="user_name" label="用户名"></textinput></template><script>
export default {
data() {
return {
user_name: 'JohnDoe' // ✅ 默认值将正确显示在输入框中
}
}
}
</script>
⚠️ 注意事项
- 不要在组件内直接修改 props.modelValue:Vue 中 props 是只读的,直接赋值会触发警告。
- 事件名必须严格为 'update:modelValue':这是 Vue 3 的标准命名,不可简写为 'input'(那是 Vue 2 的旧约定)。
- 若需支持 .lazy、.number、.trim 等修饰符,需额外监听 @change、手动转换类型或截断空格(v-model.number 对应 parseInt($event.target.value))。
- 密码可见性切换不影响 v-model 行为:showPassword 仅控制 type 属性,不干预 modelValue 流程,逻辑完全解耦。
通过以上改造,你的
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











