最近在開發(fā)一個移動端商城項目,用到了有贊的 vant ,因為最近大都采用 element ui 在做PC端的東西,對比來說,vant的完成度還是偏低了點,很多細節(jié)都雖然都實現(xiàn)了接口,但是想使用得自己去想辦法,沒辦法拿來即用。昨天用到 Uploader 圖片上傳 如是,提供了file回調(diào),卻沒有提供上傳功能,我必須給他加2個函數(shù)實現(xiàn)axios提交才能用,還有今天用到表單驗證這塊,它的 Field組件 雖然給了error-message的錯誤提示接口,但是沒有內(nèi)置表單驗證功能。
element ui 采用 async-validator 實現(xiàn)表單驗證,我也基于這個組件進行擴展,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;
}
/**
* 設定規(guī)則
* @param rules rules object async-validator rules
* @param cover 是否替換舊規(guī)則
*/
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);
}
}
/**
* 執(zhí)行驗證
* @param callback(errors, fields)
* @param data 可選 傳空將驗證構造data 傳string或數(shù)組驗證構造data的響應字段
* 以上參數(shù)順序可互轉(zhuǎn)
*/
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' : '發(fā)送'}}
</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('發(fā)送成功');
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>
還有待完善的地方,湊合著能用了