【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>
相关推荐
子兮曰2 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰2 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万2 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝2 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
A黄俊辉A2 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
三十而立洋2 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁2 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄2 天前
JavaScript 隐式全局变量解析
javascript
honkun62 天前
vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vue.js·vxe-table
kybs19913 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net