You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 16:31:09