最近在开发一个移动端商城项目,用到了有赞的 vant ,因为最近大都采用 element ui 在做PC端的东西,对比来说,vant的完成度还是偏低了点,很多细节都虽然都实现了接口,但是想使用得自己去想办法,没办法拿来即用。昨天用到 Uploader 图片上传 如是,提供了file回调,却没有提供上传功能,我必须给他加2个函数实现axios提交才能用,还有今天用到表单验证这块,它的 Field组件 虽然给了error-message的错误提示接口,但是没有内置表单验证功能。
element ui 采用 async-validator 实现表单验证,我也基于这个组件进行扩展,async-validator不支持细粒化验证,于是先对它进行扩展
validator.js
import asyncValidator from 'async-validator'
class validator {
/**
* 构造
* @param rules object async-validator rules
* @param data 初始对象
*/
constructor(rules, data) {
this.setData(data);
this.setRules(rules);
}
/**
* 重新定义初始对象
* 也可以直接修改实例的data
* validator.data = newData
* @param data
*/
setData(data) {
this.data = data;
}
/**
* 设定规则
* @param rules rules object async-validator rules
* @param cover 是否替换旧规则
*/
setRules(rules, {cover} = {}) {
if (cover === undefined || cover) {
this.validators = {};
}
for (let attr in rules) {
const rule = {};
rule[attr] = rules[attr];
this.validators[attr] = new asyncValidator(rule);
}
}
/**
* 执行验证
* @param callback(errors, fields)
* @param data 可选 传空将验证构造data 传string或数组验证构造data的响应字段
* 以上参数顺序可互转
*/
validate(callback, data) {
let cb,d;
if (typeof callback === 'function' ){
cb = callback;
d = data;
}else if (typeof data === 'function' ){
cb = data;
d = callback;
}
let _d = d;
if (this.data) {
if (!d) {
_d = this.data;
} else if (typeof d === 'string') {
_d = {};
_d[d] = this.data[d]
} else if (Array.isArray(d)) {
_d = {};
d.forEach(attr => {
_d[attr] = this.data[attr]
})
}
}
const err = [];
if (_d) {
for (let attr in _d) {
if (this.validators[attr]) {
const o = {};
o[attr] = _d[attr];
this.validators[attr].validate(o, (error) => {
if (error) {
err.push(error[0])
}
})
}
}
}
cb && cb(err.length > 0, err)
}
}
export default function (rules, data) {
return new validator(rules, data)
}
demo.vue
<template>
<div>
<van-cell-group>
<van-field
placeholder="名称/姓名"
label="名称"
v-model="data.name"
:error-message="errorMsg.name"
></van-field>
<van-field
type="tel"
placeholder="请输入手机号码"
label="手机"
v-model="data.mobile"
:error-message="errorMsg.mobile"
@click-icon="data.mobile = ''"
icon="clear"
></van-field>
<van-field
center
v-model="data.code"
label="短信验证码"
placeholder="请输入验证码"
icon="clear"
:error-message="errorMsg.code"
@click-icon="data.code = ''"
>
<van-button
slot="button"
size="small"
:disabled="countdown > 0"
@click="sendMobileCode"
type="primary">
{{ countdown ? countdown + 's' : '发送'}}
</van-button>
</van-field>
</van-cell-group>
<div class="pad-all mar-top">
<van-button
block
type="primary"
@click="submit">
立即注册
</van-button>
<van-button
block
class="mar-top"
@click="reset">
重置
</van-button>
</div>
</div>
</template>
<script>
import {Field, CellGroup, Cell, Button, Toast} from 'vant';
import validator from './validator.js'
export default {
name: 'Demo',
components: {
[Field.name]: Field,
[Button.name]: Button,
[Cell.name]: Cell,
},
data() {
return {
countdown: 0,
data: {
name: '',
mobile: '',
code: '',
},
errorMsg: {
name: '',
mobile: '',
code: '',
},
rules: {
name: [
{required: true, message: '请输入名称'}
],
mobile: [
{
validator: (rule, value, callback) => {
if (!value) {
callback('请输入手机号码');
} else if (/^[1][0-9]{10}$/.test(value)) {
callback();
} else {
callback('请输入正确的手机号码');
}
}
}
],
code: [
{required: true, message: '请输入验证码'}
]
},
}
},
methods: {
sendMobileCode() {
this.validate(errors => {
if (!errors) {
Toast('发送成功');
this.countdown = 60;
this.countdownSubtract();
}
}, 'mobile')
},
countdownSubtract() {
if (this.countdown > 0) {
setTimeout(() => {
this.countdown -= 1;
this.countdownSubtract()
}, 1000)
}
},
/**
* 清除验证提示
* @param attrs
*/
resetField(attrs) {
attrs = !attrs ? Object.keys(this.errorMsg) : ( Array.isArray(attrs) ? attrs : [attrs]);
attrs.forEach(attr => {
this.errorMsg[attr] = ''
})
},
/**
* 验证方法
* @param callback
* @param data
*/
validate(callback, data) {
this.validator.validate((errors, fields) => {
this.resetField();
if (errors) {
fields.forEach(item => {
this.errorMsg[item.field] = item.message
})
}
callback && callback(errors, fields)
}, data);
},
submit() {
this.validate((errors, fields) => {
})
},
reset() {
this.data = {
name: '',
code: '',
mobile: '',
};
this.validator.setData(this.data);
this.resetField();
},
},
created() {
this.validator = validator(this.rules, this.data);
},
}
</script>
还有待完善的地方,凑合着能用了