【Vue3】Element Plus 表单显示自定义校验错误

在开发中,遇到这个需求:前端表单通过初步校验发送给后端,但后端业务逻辑(如:数据库查重、时间冲突等)返回了具体的错误信息。业务希望将这些错误直接显示在 el-form-item 的错误提示位置。大概效果如下:

基础校验如下

javascript 复制代码
const rules = ref({
  start_time: [{ required: true, message: "请输入时间", trigger: "blur" }],
  location: [{ required: true, message: "请输入地点", trigger: "blur" }],
  pant: [{ required: true, message: "请输入参与者", trigger: "blur" }],
  evt_desc: [
    { required: true, message: "请请输入描述", trigger: "blur" },
    { min: 0, max: 30, message: "描述不超过 30 个字符", trigger: "blur" },
  ],
});

遇到的问题:

直接给 :error 属性赋值,首次没问题,错误正产显示,但第二次点击提交时校验消息就不再显示了。
原因:

Element Plus 的 el-form-item 提供了 :error 属性。

当给这个属性赋值时,它会强制显示该错误提示,并覆盖原有的 rules 校验信息。

因为form.validate() 是异步过程,其内部维护的校验状态更新可能与手动赋值 :error 的操作产生竞争关系,导致手动赋的值被组件内部逻辑重置。
解决

使用 nextTick(或延时)确保后端错误能稳定渲染

代码示例:

javascript 复制代码
<template>
  <div>
    <el-form ref="formRef" :model="form" :rules="rules" label-position="top">
      
      <el-form-item label="事件描述" prop="evt_desc" :error="backendErrors.evt_desc">
        <el-input v-model="form.evt_desc" placeholder="请输入描述" />
      </el-form-item>

      <el-button type="primary" :loading="loading" @click="handleSubmit">
        开始
      </el-button>
    </el-form>
  </div>
</template>

<script setup>
import { reactive, ref, nextTick } from 'vue';

const formRef = ref();
const loading = ref(false);

// 存储后端返回的错误映射
const backendErrors = reactive({
  evt_desc: ""
});

const form = reactive({
  evt_desc: ""
});

const rules = {
  evt_desc: [{ required: true, message: "前端校验:请输入内容", trigger: "blur" }]
};

// 模拟后端接口
async function mockApi() {
  return new Promise((_, reject) => {
    setTimeout(() => {
      // 模拟后端校验不通过返回的数据
      reject({
        message: JSON.stringify({ evt_desc: "后端反馈:该描述已存在,请更换" })
      });
    }, 500);
  });
}

// 提交逻辑
async function handleSubmit() {
  if (!formRef.value) return;

  formRef.value.validate(async (valid) => {
    if (!valid) return;
    
    loading.value = true;
    try {
      await mockApi();
      // 成功逻辑...
    } catch (err) {
      // 清空旧的后端错误
      Object.keys(backendErrors).forEach(key => backendErrors[key] = "");

      // 解析错误并赋值
      const errorMap = JSON.parse(err.message);
      
      // ==== 这个是关键 ====
      await nextTick(); 
      
      for (const key in errorMap) {
        if (key in backendErrors) {
          backendErrors[key] = errorMap[key];
        }
      }
    } finally {
      loading.value = false;
    }
  });
}
</script>
相关推荐
lichenyang4532 小时前
Docker 学习笔记(一):为什么需要镜像、容器和仓库?
前端
kyriewen3 小时前
别再对着 TypeScript 报错发呆了:我把 10 个最常见的红色波浪线翻译成了人话
前端·javascript·typescript
IT_陈寒3 小时前
SpringBoot自动配置的坑,我的API突然就404了
前端·人工智能·后端
free353 小时前
从 0 实现一个 Tiny JavaScript VM:项目架构拆解
javascript
暴走的小呆3 小时前
Vue 2 中 Object 的变化侦测:从 getter/setter 到 Dep、Watcher、Observer
vue.js
奇奇怪怪的4 小时前
Embedding 模型 10+ 横向评测
前端
陈广亮4 小时前
Monorepo 从 0 到 1 实操指南 2026 版:pnpm catalogs + Turborepo 2.x + changesets 全链路
前端
子兮曰4 小时前
OpenMontage 深度解剖:你的 AI 编程助手,其实是个视频工作室
前端·后端·ai编程
敲代码的鱼4 小时前
PDF 预览与签名批注写回 支持安卓 iOS 鸿蒙 UTS插件
android·前端·ios
英勇无比的消炎药4 小时前
TinyVue v-auto-tip: 文本超长自动提示的优雅方案
vue.js