樹醬但願將前端的樂趣帶給你們 本文已收錄 github.com/littleTreem… 喜歡就star✨前端
前言:這段時間一直在搞to B方向中後臺的項目,表單接觸的頻率會比較多,就突發奇想聊聊表單數據相關的一些基礎分享vue
當表單在視圖所展現的數據並非後端須要的數據,或者後端返回的數據不是前端所要展現的內容,這時就須要進行數據轉換,下面介紹幾種常見的場景git
我假設有下面的一組form基礎數據github
data(){
return {
form:{
name: '商品名稱',
id: '訂單編號',
nickName: '商品別名',
num: '商品數量',
price:'價格',
tag: '0' // 1 表示特價 0 表示無特價
},
}
},
複製代碼
場景:當前端form中的數據存在冗餘的字段,也就是說後端並不須要這些字段,咱們能夠經過過濾把沒必要要的字段篩選掉後端
const noRequired = ['tag', 'nickName']; //不須要的字段
const formData = Object.keys(this.form)
.filter(each => !noRequired.includes(each))
.reduce((acc, key) => (acc[key] = this.form[key], acc), {});
複製代碼
場景:後端不須要表單數據那麼多數據,只須要一部分時能夠用前端工程化
const formData= JSON.parse(
JSON.stringify(this.form,["nickName","price"])
);
複製代碼
場景:當前表單有部分字段須要替換或覆蓋新的數據時可用bash
Object.assign(this.form, {
tag: '商品1'
}
複製代碼
當前表單字段須要映射爲其餘字段名稱時可用,以下對應的name的key值換爲Name服務器
const formData = JSON.parse(
JSON.stringify(this.form).replace(
/name/g,
'Name')
);
複製代碼
const mapObj = {
name: "Name",
nickName: "NickName",
tag: "Tag"
};
const formData = JSON.parse(
JSON.stringify(this.form).replace(
/name|nickName|tag/gi,
matched => mapObj[matched])
);
複製代碼
ps:這種方式有bug,你知道是什麼嗎?運維
當字段存在0,1等狀態數,須要轉換成爲相對應的表示時可用,以下對應的tag字段,0對應特價,1對應無特價,進行映射轉換frontend
const formData = JSON.parse(JSON.stringify(this.form,(key,value)=>{
if(key == 'tag'){
return ['特價','無特價'][value];
}
return value;
}));
複製代碼
數據合併,將表單數據字段合併,注意的是,若是字段相同,會覆蓋前面表單數據字段的數值
const query = { tenaId: '訂單編號', id:'查詢ID'}
const formData = {
...this.form,
query
}
複製代碼
當表單數據填寫完成,須要進一步作表單提交傳送後端服務器,可是前端須要作數據的進一步確實是否符合規則,好比是否爲必填項、是否爲手機號碼格式
data() {
return {
schema:{
phone: {
required:true
},
}
};
},
methods: {
// 判斷輸入的值
validate(schema, values) {
for(field in schema) {
if(schema[field].required) {
if(!values[field]) {
return false;
}
}
}
return true;
},
}
console.log(this.validate(schema, {phone:'159195**34'}));
複製代碼
data() {
return {
phoneForm: {
phoneNumber: '',
verificationCode: '',
tips:''
},
schema:{
phoneNumber: [{required: true, error: '手機不能爲空'}, {
regex: /^1[3|4|5|6|7|8][0-9]{9}$/,
error: '手機格式不對',
}],
verificationCode: [{required: true, error: '驗證碼不能爲空'}],
}
};
},
methods: {
// 判斷輸入的值
validate(schema, values) {
const valArr = schema;
for (const field in schema) {
if (Object.prototype.hasOwnProperty.call(schema, field)) {
for (const key of schema[field]) {
if (key.required) {
if (!valArr[field]) {
valArr.tips = key.error;
return false;
}
} else if (key.regex) {
if (!new RegExp(key.regex).test(valArr[field])) {
valArr.tips = key.error;
return false;
}
}
}
}
}
return true;
},
}
console.log(this.validate(this.schema, this.phoneForm);
複製代碼
Iview 的 Form 組件模塊主要由Form 和 FormItem組成
咱們能夠清晰看到,iview的 form 組件是經過async-validator工具庫來做爲表單驗證的方法
官方例子以下👇 文檔連接
import schema from 'async-validator';
var descriptor = {
address: {
type: "object", required: true,
fields: {
street: {type: "string", required: true},
city: {type: "string", required: true},
zip: {type: "string", required: true, len: 8, message: "invalid zip"}
}
},
name: {type: "string", required: true}
}
var validator = new schema(descriptor);
validator.validate({ address: {} }, (errors, fields) => {
// errors for address.street, address.city, address.zip
});
複製代碼
而在iview的 form 組件中主要定義了validate函數中使用 field.validate就是調用async-validator的方法,用來管理form-item組件下的驗證
// ViewUI/src/components/form/form.vue
methods:{
validate(callback) {
return new Promise(resolve => {
let valid = true;
let count = 0;
this.fields.forEach(field => {
field.validate('', errors => {
if (errors) {
valid = false;
}
// 檢驗已完成的校驗的數量是否徹底,則返回數據有效
if (++count === this.fields.length) {
// all finish
resolve(valid);
if (typeof callback === 'function') {
callback(valid);
}
}
});
});
});
},
//針對單個的校驗
validateField(prop, cb) {
const field = this.fields.filter(field => field.prop === prop)[0];
if (!field) {throw new Error('[iView warn]: must call validateField with valid prop string!'); }
field.validate('', cb);
}
//表單規則重置
resetFields() {
this.fields.forEach(field => {
field.resetField();
});
},
},
created () {
//經過FormItem定義的prop來收集須要校驗的字段,
this.$on('on-form-item-add', (field) => {
if (field) this.fields.push(field);
return false;
});
// 移除不須要的字段
this.$on('on-form-item-remove', (field) => {
if (field.prop) this.fields.splice(this.fields.indexOf(field), 1);
return false;
});
}
複製代碼
Form.vue 中涉及到的 this.fields 裏面的規則 是在其create生命週期時經過監聽‘on-form-item-add’push進來的,‘on-form-item-add’事件是由form-item 組件 觸發相對應的事件,並傳入相對應的實例就能夠建立數據的關聯,如下是form-item的生命週期函數內容:
// ViewUI/src/components/form/form-item.vue
mounted () {
// 若是定義了須要驗證的字段
if (this.prop) {
// 向父親Form組件添加field
this.dispatch('iForm', 'on-form-item-add', this);
Object.defineProperty(this, 'initialValue', {
value: this.fieldValue
});
this.setRules();
}
},
beforeDestroy () {
// 移除以前刪除form中的數據字段
this.dispatch('iForm', 'on-form-item-remove', this);
}
methods: {
setRules() {
//獲取全部規則
let rules = this.getRules();
if (rules.length&&this.required) {
return;
}else if (rules.length) {
rules.every((rule) => {
this.isRequired = rule.required;
});
}else if (this.required){
this.isRequired = this.required;
}
this.$off('on-form-blur', this.onFieldBlur);
this.$off('on-form-change', this.onFieldChange);
this.$on('on-form-blur', this.onFieldBlur);
this.$on('on-form-change', this.onFieldChange);
},
getRules () {
let formRules = this.form.rules;
const selfRules = this.rules;
formRules = formRules ? formRules[this.prop] : [];
return [].concat(selfRules || formRules || []);
},
validate(trigger, callback = function () {}) {
let rules = this.getFilteredRule(trigger);
if (!rules || rules.length === 0) {
if (!this.required) {
callback();
return true;
}else {
rules = [{required: true}];
}
}
// 設置AsyncValidator的參數
this.validateState = 'validating';
let descriptor = {};
descriptor[this.prop] = rules;
const validator = new AsyncValidator(descriptor);
let model = {};
model[this.prop] = this.fieldValue;
validator.validate(model, { firstFields: true }, errors => {
this.validateState = !errors ? 'success' : 'error';
this.validateMessage = errors ? errors[0].message : '';
callback(this.validateMessage);
});
this.validateDisabled = false;
},
}
複製代碼
感興趣小夥伴能夠在這個基礎上經過源碼的學習深刻研究iview組件庫的form表單校驗的具體實現。
element的ElForm表單組件校驗原理跟上一節講的iview組件庫很像,這裏就不作大篇幅介紹說明,直接「上才藝」-----源碼連接
經過不一樣正則規則,來約束不一樣類型的表單數據是否符合要求
/^1[3|4|5|6|7|8][0-9]{9}$/
/^[0-9]+$/
/^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/
/^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/
/[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/
/((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}/
往期文章🔥