Vue3.4中同步vee-validate useField与v-model并修复Textarea组件
修复Vee-Validate + Vue 3 Textarea组件的disabled/readonly状态不生效问题
核心问题根源
你的问题本质是组件内部未将disabledModelValue/readonlyModelValue正确绑定到原生textarea元素,或是useField返回的状态与组件双向绑定的model未同步,导致状态仅停留在逻辑层,未传递到DOM节点。
具体修正方案
1. 规范defineModel的使用
Vue 3.4+的defineModel需明确声明类型与默认值,确保双向绑定逻辑正确:
<script setup> import { useField, watch } from 'vee-validate'; // 声明双向绑定的model,明确类型和默认值 const modelValue = defineModel({ type: String, default: '' }); const disabledModelValue = defineModel('disabledModelValue', { type: Boolean, default: false }); const readonlyModelValue = defineModel('readonlyModelValue', { type: Boolean, default: false }); // 关联Vee-Validate字段,传入初始值 const { value: fieldValue, errorMessage } = useField('textarea', undefined, { initialValue: modelValue.value, }); // 同步modelValue与fieldValue,避免输入值不同步 watch([modelValue, fieldValue], ([newModelVal, newFieldVal]) => { if (newModelVal !== newFieldVal) { modelValue.value = newFieldVal; } }); </script>
2. 绑定状态到原生textarea元素
必须将disabled和readonly属性直接绑定到textarea标签上,仅在控制台打印无法触发DOM状态变化:
<template> <div class="textarea-wrapper"> <textarea v-model="fieldValue" :disabled="disabledModelValue" :readonly="readonlyModelValue" :placeholder="placeholder" /> <span v-if="errorMessage" class="error-tip">{{ errorMessage }}</span> </div> </template>
3. 同步Vee-Validate字段状态(可选)
若需要让Vee-Validate感知组件的禁用/只读状态,可添加状态监听:
// 监听disabled状态变化,同步到Vee-Validate的field实例 watch(disabledModelValue, (newState) => { const { field } = useField('textarea'); field.value.disabled = newState; });
4. Storybook传参验证
确保Story代码中正确传递双向绑定参数:
// Textarea.stories.js export const DisabledTextarea = { args: { modelValue: '这是禁用状态的文本', disabledModelValue: true, }, }; export const ReadonlyTextarea = { args: { modelValue: '这是只读状态的文本', readonlyModelValue: true, }, };
完整修正后的Textarea.vue示例
<template> <div class="textarea-component"> <textarea v-model="syncValue" :disabled="disabledModelValue" :readonly="readonlyModelValue" :rows="rows || 3" :placeholder="placeholder || '请输入内容'" class="textarea-input" /> <p v-if="errorMessage" class="error-text">{{ errorMessage }}</p> </div> </template> <script setup> import { computed, watch } from 'vue'; import { useField } from 'vee-validate'; // 定义基础props const props = defineProps({ placeholder: String, rows: Number, }); // 双向绑定model const modelValue = defineModel({ type: String, default: '' }); const disabledModelValue = defineModel('disabledModelValue', { type: Boolean, default: false }); const readonlyModelValue = defineModel('readonlyModelValue', { type: Boolean, default: false }); // 关联Vee-Validate字段 const { value: fieldValue, errorMessage } = useField('textarea', undefined, { initialValue: modelValue.value, }); // 计算属性同步model与field值 const syncValue = computed({ get() { return fieldValue.value; }, set(val) { fieldValue.value = val; modelValue.value = val; }, }); // 同步禁用状态到Vee-Validate watch(disabledModelValue, (newState) => { const { field } = useField('textarea'); field.value.disabled = newState; }); </script> <style scoped> .textarea-input { width: 100%; padding: 0.5rem; border: 1px solid #e5e7eb; border-radius: 0.25rem; resize: vertical; } .textarea-input:disabled, .textarea-input:readonly { background-color: #f3f4f6; cursor: not-allowed; } .error-text { color: #dc2626; font-size: 0.875rem; margin-top: 0.25rem; } </style>
关键注意点
- 原生textarea的
disabled/readonly是布尔属性,必须直接绑定到元素才会生效,仅控制台打印无法触发DOM状态变更; - 必须同步
defineModel和useField返回的value,否则会出现输入值与外部组件不同步的问题; - 若使用自定义命名的model(如
disabledModelValue),需确保模板中绑定的变量名与defineModel声明完全一致。
内容的提问来源于stack exchange,提问作者Aya Abdessalem
相关产品推荐
相关产品推荐

