avue 长表单校验自动定位到错误位置

前言

在使用 avue 时有时候需要用到很长的表单,长表单保存提交且有校验错误时,如果错误位置不在滚动屏幕可视区域,此时用户看不到任何提示信息,用户需要去滚动寻找哪一项校验不通过,用户体验很不好,需要自动定位到错误位置。

解决办法

avue 官方文档中,avue-form 和 avue-crud 的错误回调方法位置非常难找,文档中只有在例子出现的 error 方法,例子如下:

<template>
  <avue-crud
    :data="data"
    v-model="obj"
    :option="option"
    @error="handleError"
  ></avue-crud>
</template>

<script setup>
import { ref } from "vue";
import { ElMessage } from "element-plus";
const obj = ref({});
const data = ref([]);

const validatePass = (rule, value, callback) => {
  if (value === "") {
    callback(new Error("请输入密码"));
  } else {
    callback();
  }
};

const validatePass2 = (rule, value, callback) => {
  if (value === "") {
    callback(new Error("请再次输入密码"));
  } else if (value !== obj.value.password) {
    callback(new Error("两次输入密码不一致!"));
  } else {
    callback();
  }
};

const option = ref({
  column: [
    {
      label: "密码",
      prop: "password",
      rules: [{ required: true, validator: validatePass, trigger: "blur" }],
    },
    {
      label: "确认密码",
      prop: "oldpassword",
      rules: [{ required: true, validator: validatePass2, trigger: "blur" }],
    },
  ],
});

const handleError = (err) => {
  ElMessage.success("请查看控制台");
  console.log(err);
};
</script>

主要使用有两个解决办法,以 avue-curd 中的新增编辑表单为例

方法一 使用 error 事件参数

根据官方文档error回调事件中返回一个object参数即未通过校验的字段,为每个字段添加相同类名,通过documen.getElementsByClassName或document.querySelector查找未通过项元素,使用scrollIntoView()定位到该元素。这个方法对有嵌套子表同样适用,子表往往不单独提交那么就不会校验触发error事件,所以父表的error回调函数对子表的错误一起处理。

实现代码

<template>
  <avue-crud :data="data"
             v-model="obj"
             :option="option"
             @error="validateFun"></avue-crud>
</template>

<script setup>
import { ref } from 'vue';
import { ElMessage } from 'element-plus';
const obj = ref({});
const data = ref([]);

const option = ref({
  column: [
    {
        label: '姓名',
        prop: 'personName',
        class: 'personName',   // 添加与prop值相同类名
        type: 'input',
        rules: [
          {
            required: true,
            message: '请输入姓名',
            trigger: 'blur',
          },
        ],
    },

          {
            label: '家庭成员信息',
            prop: 'families',
            class: 'families',
            type: 'dynamic',
            span: 24,
            children: {
              type: 'form',
              rowAdd: done => {},
              rowDel: (row, done) => {},
              column: [
                {
                  label: '姓名',
                  prop: 'memberName',
                  class: 'memberName',   // 添加与prop值相同类名
                  type: 'input',
                  rules: [
                    {
                      required: true,
                      message: '请输入姓名',
                      trigger: 'blur',
                    },
                  ],
                },
              ],
            }
        },
  ]
});

const validateFun = (err) => {
	 let errObj = Object.keys(err);
      if (errObj && errObj.length > 0){
        const field = errObj[0];
        const message = err[field][0].message;
        if (field) {
          let item = document.querySelector(`.${field}`);
          item.scrollIntoView({behavior: 'smooth'});
          ElMessage.error(message || '请填写必填项')
        }
      }
};

这个方法有个缺点就是当错误项有多个的时候,err 参数返回的项不是按从上到下的顺序的,定位不到第一个错误。方法二适用于多个错误项可以定位到第一个项。

方法二 使用 el-form 的 is-error 类名

avue-form实际上是对el-form封装的,当校验错误时,el-form会对表单项加一个is-error的类名,我们可以通过查找该类名找到报错表单项进行定位,此时找到的元素数组时按照dom树从上到下的顺序排列,可以定位第一个报错表单项。报错元素中子元素el-form-item__error是错误信息可以同时展示。

实现代码

修改上面的 validateFun 方法

<script setup>
const validateFun = (err) => {
	let isError = document.getElementsByClassName('is-error');
	if (isError.length) {
		isError[0].scrollIntoView({behavior: 'smooth'});
		const msg = isError[0].getElementsByClassName('el-form-item__error');
		setTimeout(() => {
			this.$message.warning(msg[0]?.innerText || '请填写必填项');
		}, 500);
	}
},
posted @ 2025-01-09 10:42  越来越强  阅读(214)  评论(0)    收藏  举报