/**
|
* CForm - 表单套装组件,套件的主体
|
* 表单容器组件,用于管理表单数据、处理表单验证和提交
|
* 支持自动滚动到错误位置,提供表单项变化回调和表单完成回调
|
* 提供手动提交、预验证和错误设置等功能
|
* @author Tevin
|
*/
|
|
<template>
|
<view
|
:class="'c-form-outer ' + (autoScrollToError==='on'?'auto-scroll':'')"
|
ref="formOuter"
|
>
|
<form
|
class="c-form"
|
v-if="autoScrollToError==='off'"
|
@submit="evt=>handleSubmit()"
|
>
|
<slot :formRes="formRes" />
|
</form>
|
<scroll-view
|
class="c-form-scroller"
|
v-else-if="autoScrollToError==='on'"
|
:scrollY="true"
|
:scroll-top="scrollTop"
|
:scroll-with-animation="true"
|
@scroll="evt => handleScroll(evt)"
|
>
|
<form
|
class="c-form"
|
@submit="evt=>handleSubmit()"
|
>
|
<slot :formRes="formRes" />
|
</form>
|
</scroll-view>
|
</view>
|
</template>
|
|
<script>
|
import Taro from '@tarojs/taro';
|
import { $ } from '@tarojs/extend';
|
import './cForm.scss';
|
|
export default {
|
name: 'CForm',
|
props: {
|
// 表单数据主体
|
formData: Object,
|
// 是否自动滚动到错误位置,on/off
|
autoScrollToError: {
|
type: String,
|
default: 'off',
|
},
|
// 表单项变化的回调
|
// 回调传参只有单项数据
|
onChange: Function,
|
// 表单完成的回调
|
// 提交且通过表单验证后调用,不通过验证不调用
|
// 回调传参包含整个表单数据
|
onFinish: Function,
|
},
|
data() {
|
return {
|
formRes: {
|
formData: this.formData,
|
},
|
validators: {},
|
scrollTop: 0,
|
offsetTop: 0,
|
};
|
},
|
methods: {
|
handleScroll(evt) {
|
this.scrollTop = evt.target.scrollTop;
|
},
|
handleSubmit() {
|
const checklist = [];
|
// 所有项验证
|
Object.keys(this.validators).forEach(key => {
|
// 仍有效的验证器
|
if (this.validators[key]) {
|
checklist.push(this.validators[key]());
|
}
|
});
|
Promise.all(checklist).then(validations => {
|
for (let validation of validations) {
|
// 第一个不通过项提示
|
if (!validation.passed) {
|
if (this.autoScrollToError === 'on') {
|
this.scrollTop = validation.offset.top - this.offsetTop;
|
}
|
Taro.showToast({
|
title: validation.msg,
|
icon: 'none',
|
mask: false,
|
duration: validation.msg.length < 16 ? 2000 : 3000,
|
});
|
return;
|
}
|
}
|
// 所有检查通过
|
this.onFinish && this.onFinish();
|
});
|
},
|
// 手工提交
|
$submit() {
|
this.handleSubmit();
|
},
|
// 提前验证指定项
|
$preVerify(keys, callback) {
|
const checklist = [];
|
// 从选定的项中验证
|
keys.forEach(key => {
|
// 效的验证器
|
if (this.validators[key]) {
|
checklist.push(this.validators[key]('msgOnly'));
|
}
|
});
|
Promise.all(checklist).then(validations => {
|
for (let validation of validations) {
|
// 第一个不通过项提示
|
if (!validation.passed) {
|
if (this.autoScrollToError === 'on') {
|
this.scrollTop = validation.offset.top - this.offsetTop;
|
}
|
Taro.showToast({
|
title: validation.msg,
|
icon: 'none',
|
mask: false,
|
duration: validation.msg.length < 16 ? 2000 : 3000,
|
});
|
// 检查失败
|
callback && callback(false);
|
return;
|
}
|
}
|
// 所有检查通过
|
callback && callback(true);
|
});
|
},
|
// 直接设定错误
|
$setErrors(errors) {
|
const checklist = [];
|
const unchecks = [];
|
Object.keys(errors).forEach(errorKey => {
|
if (typeof this.validators[errorKey] !== 'undefined') {
|
checklist.push(
|
this.validators[errorKey]('setError', errors[errorKey]),
|
);
|
} else {
|
unchecks.push(errors[errorKey]);
|
}
|
});
|
if (checklist.length > 0) {
|
Promise.all(checklist).then(validations => {
|
for (let validation of validations) {
|
// 第一个不通过项提示
|
if (!validation.passed) {
|
if (this.autoScrollToError === 'on') {
|
this.scrollTop = validation.offset.top - this.offsetTop;
|
}
|
Taro.showToast({
|
title: validation.msg,
|
icon: 'none',
|
mask: false,
|
duration: validation.msg.length < 16 ? 2000 : 3000,
|
});
|
return;
|
}
|
}
|
});
|
} else if (unchecks.length > 0) {
|
Taro.showToast({
|
title: unchecks[0],
|
icon: 'none',
|
mask: false,
|
duration: unchecks[0] < 16 ? 2000 : 3000,
|
});
|
}
|
},
|
$setScrollTop(top) {
|
if (this.autoScrollToError === 'on') {
|
this.scrollTop = top;
|
}
|
},
|
},
|
mounted() {
|
// 当表单项变化时
|
this.formRes.$handleChange = (evt = []) => {
|
Object.keys(evt).forEach(key => {
|
// 直接改值
|
if (typeof this.formRes.formData[key] === 'undefined') {
|
this.$set(this.formRes.formData, key, evt[key]);
|
} else {
|
this.formRes.formData[key] = evt[key];
|
}
|
});
|
this.onChange && this.onChange(evt);
|
};
|
// 注册表单验证器
|
this.formRes.$regItemValidator = (name, cb) => {
|
this.validators[name] = cb;
|
};
|
// 表单滚动偏移
|
if (this.autoScrollToError === 'on') {
|
setTimeout(() => {
|
$(this.$refs.formOuter)
|
.offset()
|
.then(offset => {
|
this.offsetTop = offset.top + 10;
|
});
|
}, 10);
|
}
|
},
|
beforeDestroy() {
|
this.validators = {};
|
},
|
};
|
</script>
|