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);
}
},

浙公网安备 33010602011771号