二次封装el-form
新增校验错误自动滚动到错误表单项位置
通过二次封装的方式新增了
errorScroll
属性,开启后,当表单校验失败时,会自动滚动到第一个错误表单项位置。 重写el-form
的validate
方法,添加校验失败是滚动逻辑,用法与el-form
一致。resetFields
、clearValidate
、validateField
方法也通过重写调用原来方法保持与el-form
一致。el-form
的$attrs
和$listeners
会透传到el-form
,所以不需要再在my-el-form
中定义$attrs
和$listeners
,直接使用el-form
的$attrs
和$listeners
即可。
my-el-form.vue
<template>
<el-form
ref="originalForm"
v-bind="$attrs"
v-on="$listeners"
class="my-el-form"
>
<slot />
</el-form>
</template>
<script>
import { isHidden, isInViewport } from './utils'
export default {
name: "MyElForm",
props: {
// 是否开启表单校验错误时滚动到错误项
errorScroll: {
type: Boolean,
default: null
}
},
methods: {
errorScrollToField(field) {
const el = field.$el
// 判断是否在可视区,不在可视区滚动到可视区
if (!isInViewport(el)) {
el.scrollIntoView({
behavior: 'smooth',
block: 'center',
inline: 'center'
})
}
},
handleErrorScroll(errors) {
const fields = this.$refs.originalForm.fields
for (let i = 0; i < fields.length; i++) {
const field = fields[i]
// 找到第一个错误非隐藏元素的表单项
if (errors[field.prop] && !isHidden(field.$el)) {
// 执行滚动逻辑
this.errorScrollToField(field)
break
}
}
},
// 重写 resetFields
resetFields() {
this.$refs['originalForm'].resetFields()
},
// 重写 clearValidate
clearValidate(props = []) {
this.$refs['originalForm'].clearValidate(props)
},
// 重写 validate
validate(callback) {
let promise
// 判断是否有回调,如果没有,则返回promise。保持用法一致
if (typeof callback !== 'function' && window.Promise) {
promise = new window.Promise((resolve, reject) => {
callback = function(valid, invalidFields) {
if (valid) {
resolve(valid)
} else {
reject(invalidFields)
}
}
})
}
this.$refs['originalForm'].validate((valid, invalidFields) => {
callback(valid, invalidFields)
if (!valid && this.errorScroll) {
// 滚动到第一个错误表单
this.handleErrorScroll(invalidFields)
}
})
return promise
},
// 重写 validateField
validateField(props, cb) {
this.$refs['originalForm'].validateField(props, cb)
}
}
}
</script>
utils
/**
* 判断元素是否在可视区域
* @param el
* @returns {boolean}
*/
export function isInViewport(el) {
const rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
/**
* 判断元素是否隐藏
* @param el
* @returns {boolean}
*/
export function isHidden(el){
return el.offsetParent === null;
}
关于scrollIntoView
的使用
scrollIntoView 是一个可以在浏览器中使元素滚动到视口内的方法。它属于 Element 接口,因此任何 DOM 元素都可以调用这个方法。以下是 scrollIntoView 的基本用法:
基本
element.scrollIntoView();
参数
behavior
: 滚动动画的行为,可以是auto
或smooth
。block
: 指定垂直方向上的滚动行为,可以是start
,center
,end
, 或nearest
。inline
: 指定水平方向上的滚动行为,与block
类似。
element.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' });
请注意,
scrollIntoView
方法在不同的浏览器中可能有不同的支持情况,尤其是对于参数的支持。 现代浏览器(如 Chrome, Firefox, Safari)通常支持带有参数的版本,但在一些旧版或低版本的浏览器中,可能只能使用无参数的版本。 如果你在使用scrollIntoView
时遇到兼容性问题,可以考虑使用 JavaScript 库或 polyfill 来增强其跨浏览器的兼容性。