Video by Abbat Studio on Pexels
1031 字
5 分钟
el-form之表单校验自动定位到报错位置
本文同步自 CSDN · 清阿哥,原文发布于 2022-07-09。
1. 背景
表单校验大多数的表单都会用到,一般情况下只是提示当前哪些项校验不通过,但是如果表单比较需要用户自己去找是哪项校验不通过,这样的用户体验不太好,如果能自动定位到当前校验不通过的表单项体验会更好一些(这里是以elementui 的 el-from 组件为例子)
2. 实现思路
目前有两个实现方法:
- 方法一:
- 表单校验不通过的时候,会在未校验成功的表单 el-form-item 标签上加一个类名 is-error,可以从这个类名下手,获取当前校验不通过的所有的类名,然后通过 scrollIntoView 方法进行自动滑动到当前报错的表单项位置

- 表单校验不通过的时候,会在未校验成功的表单 el-form-item 标签上加一个类名 is-error,可以从这个类名下手,获取当前校验不通过的所有的类名,然后通过 scrollIntoView 方法进行自动滑动到当前报错的表单项位置
- 方法二:
- 利用el-form提供的 validate 方法的第二个参数,获取当前校验不通过的rule 对象,获取到报错的 prop 后,在每个需要加表单校验的项上加上 ref,ref 的绑定值和 prop 保持一致这样方便直接定位到哪个prop,然后和第一个方法一样利用 scrollIntoView 方法结合el 实现自动定位到校验不通过的表单项

- 利用el-form提供的 validate 方法的第二个参数,获取当前校验不通过的rule 对象,获取到报错的 prop 后,在每个需要加表单校验的项上加上 ref,ref 的绑定值和 prop 保持一致这样方便直接定位到哪个prop,然后和第一个方法一样利用 scrollIntoView 方法结合el 实现自动定位到校验不通过的表单项
3. 实现代码
方法一实现代码:
// 表单校验 verifyForm() { this.$refs.basicInfoRule.validate(valid => { if (valid) { // 校验通过执行的逻辑 } else { // 校验不通过自动定位到不通过的表单项 this.moveToErr() } }) },
// 自动定位到表单报错项 moveToErr() { this.$nextTick(() => { let isError = document.getElementsByClassName('is-error') if (isError.length) { isError[0].scrollIntoView({ block: 'center', behavior: 'smooth' }) // 这个当滑动到报错项之后自动获取输入框的焦点,方便用户直接进行输入,延迟 800ms 是因为需要都能到定位成功后在进行获取焦点体验更好一些 setTimeout(() => { if (isError[0].previousElementSibling.querySelector('input')) { isError[0].previousElementSibling.querySelector('input').focus() } }, 800) } }) }方法二实现代码:
模板示例代码
<el-form-item label="姓名:" prop="name" ref="name"> <el-input v-model.number="form." placeholder="请输入姓名" clearable ></el-input> </el-form-item> verifyForm() { this.$refs.ruleForm.validate((valid, object) => { if (valid) { //校验通过执行逻辑 } else { let errorArr = []; for (let key in object) { object[key].forEach((item) => { errorArr.push(item.message); }); let dom = this.$refs[Object.keys(object)[0]]; if (Object.prototype.toString.call(dom) !== '[object Object]') { dom = dom[0]; break; //结束语句并跳出语句,进行下个语句执行 } // 定位到报错项 dom.$el.scrollIntoView({ block: 'center', behavior: 'smooth', }); } // 页面提示未通过校验字段项, this.$message.error(errorArr[0]); } }); },5. 拓展(踩坑…)
由于页面比较复杂分了好几个子组件,而且子组件中都有需要校验的表单项,在父组件保存表单前,需要调用各个子组件的表单校验方法,发现el-form 的 validate 方法不能返会校验失败还是校验成功
错误代码示范:
// 子组件代码 verifyForm() { this.$refs.basicInfoRule.validate(valid => { if (valid) { // 校验通过 return true } else { // 校验不通过 return false } }) },
// 父组件代码 // 校验子组件表单(通过子组件绑定的ref来调用子组件的校验方法) async handleVerify() { if ( !(await this.$refs.basicInfo?.verifyForm()) || !(await this.$refs.priceSetting?.verifyForm()) ) { this.$message.warning('请完善表单必填项') return false } return true }, // 保存 async saveMainDetail() { try { if (!(await this.handleVerify())) return } catch (e) {}上述代码在父组件里面不能获取到组件的校验状态,子组件换一个写法就行了
正确代码示范:
使用 Promise 来返回表单的是否校验成功状态能在父组件成功拿到了
// 子组件代码 verifyForm() { return new Promise((resolve, reject) => { this.$refs.basicInfoRule.validate(valid => { if (valid) { console.log(valid, '校验通过') resolve(true) } else { console.log(valid, '校验不通过') reject(new Error()) } }) }) }6. 结语
实现功能的思路有很多,这里我列举出来的两种,看实际的功能和需求找到适合自己的方法,有错误的地方还望指出,有疑问欢迎留言交流,如果你有更好的方法也希望不吝赐教,如果能帮到你我很荣幸~
el-form之表单校验自动定位到报错位置
https://qingge-cabana.vercel.app/posts/el-form之表单校验自动定位到报错位置-125689424/ 
评论 待开启
评论基于 GitHub Discussions(Giscus)。仓库推送并开启 Discussions 后,在 giscus.app 获取
repoId/categoryId,填入src/config.ts的giscusConfig即可。HHQ-666/qingge-blog