[go: up one dir, main page]

Skip to content

Commit

Permalink
增加了表单集中校验的功能
Browse files Browse the repository at this point in the history
  • Loading branch information
wuhao000 committed Jul 7, 2019
1 parent 7966b7e commit c6d1d8e
Show file tree
Hide file tree
Showing 15 changed files with 513 additions and 235 deletions.
7 changes: 6 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"component-classes": "^1.2.6",
"core-js": "^2.6.5",
"cssbeautify": "^0.3.1",
"debounce": "^1.2.0",
"dom-scroll-into-view": "^1.2.1",
"enquire.js": "^2.1.6",
"exenv": "^1.2.2",
Expand Down
9 changes: 6 additions & 3 deletions src/generated/list/demo1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@
</ul>
</div>
</m-list-item>
<m-list-item extra-position="left" extra="这是我的值">Extra Left</m-list-item>
<m-list-item extra-position="center" extra="这是我的值">Extra Center</m-list-item>
<m-list-item extra="这是我的值"
extra-position="left">Extra Left
</m-list-item>
<m-list-item extra="这是我的值"
extra-position="center">Extra Center
</m-list-item>
<m-list-item extra="这是我的值">Extra Right</m-list-item>
</m-list>
</div>
Expand All @@ -28,7 +32,6 @@
name: 'Demo1'
})
export default class Demo1 extends Vue {
// TODO
}
</script>
<style scoped lang="less">
Expand Down
7 changes: 6 additions & 1 deletion src/generated/list/demo3.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
<div style="background:#f8f8f8;">
<m-list style="margin-bottom:15px;">
<m-input v-model="form.text"
title="文本"/>
title="文本"
:rules="rules.text"/>
<m-textarea v-model="form.longText"
title="长文本"/>
<m-checkbox-popup-list v-model="form.multiSelect"
Expand Down Expand Up @@ -33,6 +34,7 @@
</div>
</template>
<script lang="ts">
import {ValidateRules} from 'async-validator';
import Vue from 'vue';
import Component from 'vue-class-component';
import MList from '../../index';
Expand All @@ -56,6 +58,9 @@
}, {
label: '选项2', value: '2'
}];
public rules: ValidateRules = {
text: [{required: true, message: '必须填'}]
};
}
</script>
<style scoped lang="less">
Expand Down
3 changes: 1 addition & 2 deletions src/mixins/base-input-component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ export default class BaseFormComponent extends mixins(PureInputComponent, FormCo
...this.getProps(),
disabled: this.isDisabled,
readOnly: this.isReadonly,
visible: this.stateValue,
size: this.componentSize
visible: this.stateValue
};
}

Expand Down
48 changes: 0 additions & 48 deletions src/mixins/form-component.ts

This file was deleted.

179 changes: 179 additions & 0 deletions src/mixins/form-component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import Emitter from './emitter';
import {getPropByPath} from './utils';
import AsyncValidator, {ValidateRule} from 'async-validator';
import debounce from 'lodash.debounce';
import Component from 'vue-class-component';
import {Inject, Prop, Watch} from 'vue-property-decorator';


const noop = function noop(a?, b?) {
};

@Component({
name: 'FormComponent'
})
export class FormComponent extends Emitter {

/**
* class 前缀
*/
@Prop({type: String})
public prefixCls?: string;
@Prop({type: Boolean})
public disabled: boolean;
@Prop({type: Boolean, default: false})
public error: boolean;
@Prop({type: String})
public errorMessage: string;
public currentErrorMessage = this.errorMessage;
public isCurrentError = this.error;
@Inject({from: 'list', default: undefined})
public list: any;
@Prop({type: String})
public prop: string;
@Prop({type: Boolean})
public readOnly: boolean;
/**
* 是否必须
*/
@Prop({type: Boolean, default: false})
public required: boolean;
@Prop({type: Array})
public rules: ValidateRule[];
public validateStatus: '' | 'success' | 'warning' | 'error' | 'validating' = '';
@Prop()
public value: any;
public currentValue = this.value;
private validateDisabled: boolean = true;

get fieldValue() {
return this.currentValue;
}

get errorIcon() {
return this.isCurrentError ? (
<div
class={`${this.prefixCls}-error-extra`}
onClick={(e) => {
if (this.currentErrorMessage && this.$toast) {
this.$toast.info(this.currentErrorMessage);
}
this.$emit('error-click', e);
}}
/>
) : null;
}

get isDisabled() {
let disabled = this.disabled;
if (this.list) {
if (!disabled) {
disabled = this.list.disabled;
}
}
return disabled;
}

get isReadonly() {
let isReadonly = this.readOnly;
if (this.list) {
if (!isReadonly) {
isReadonly = this.list.readOnly;
}
}
return isReadonly;
}

public created() {
if (this.list) {
this.dispatch('DForm', 'd.form.addField', [this]);
}
this.validate = debounce(this.validate, 300);
}

@Watch('error')
public errorChanged(error: boolean) {
this.isCurrentError = error;
}

@Watch('errorMessage')
public errorMessageChanged(errorMessage: string) {
this.currentErrorMessage = errorMessage;
}

public getFilteredRule(trigger) {
const rules = this.getRules();
return rules.filter(rule => {
if (!rule.trigger || trigger === '') {
return true;
}
if (Array.isArray(rule.trigger)) {
return rule.trigger.indexOf(trigger) > -1;
} else {
return rule.trigger === trigger;
}
}).map(rule => Object.assign({}, rule));
}

public getRules(): ValidateRule[] {
let formRules: any = this.list && this.list.rules;
const prop = getPropByPath(formRules, this.prop || '');
formRules = formRules ? (prop.o[this.prop || ''] || prop.v) : [];
const selfRules = this.rules;
let requiredRule = this.required !== undefined ? {required: this.required} : [];
if ((formRules && formRules.some(rule => rule.required !== undefined))
|| (selfRules && selfRules.some(rule => rule.required !== undefined))) {
requiredRule = [];
}
return [].concat(selfRules || formRules || []).concat(requiredRule);
}

public onFieldBlur() {
this.validate('blur');
}

public onFieldChange() {
if (this.validateDisabled) {
this.validateDisabled = false;
return;
}
this.validate('change');
}

public validate(trigger, callback = noop) {
this.$nextTick(() => {
this.validateDisabled = false;
const rules = this.getFilteredRule(trigger);
if ((!rules || rules.length === 0) && this.required === undefined) {
callback();
return true;
}
this.validateStatus = 'validating';
const descriptor = {};
if (rules && rules.length > 0) {
rules.forEach(rule => {
delete rule.trigger;
});
}
descriptor[this.prop] = rules;
const validator = new AsyncValidator(descriptor);
const model = {
[this.prop]: this.fieldValue
};
validator.validate(model, {firstFields: true}, (errors, invalidFields) => {
this.validateStatus = !errors ? 'success' : 'error';
this.isCurrentError = this.validateStatus === 'error';
this.currentErrorMessage = errors ? errors[0].message : '';
callback(this.currentErrorMessage, invalidFields);
this.$emit('validate', !errors, errors);
this.list && this.list.$emit('validate', this.prop, !errors, this.currentErrorMessage || null);
});
});
}

@Watch('value')
public valueChanged(value: any) {
this.currentValue = value;
}

}
31 changes: 31 additions & 0 deletions src/mixins/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
export const getPropByPath = function getPropByPath(obj, path, strict?) {
let tempObj = obj;
let copyPath = path;
copyPath = copyPath.replace(/\[(\w+)]/g, '.$1');
copyPath = copyPath.replace(/^\./, '');

const keyArr = copyPath.split('.');
let i = 0;
for (const len = keyArr.length; i < len - 1; ++i) {
if (!tempObj && !strict) {
break;
}
const key = keyArr[i];
if (key in tempObj) {
tempObj = tempObj[key];
} else {
if (strict) {
throw new Error('please transfer a valid prop path to form item!');
}
break;
}
}
return {
o: tempObj,
k: keyArr[i],
v: tempObj ? tempObj[keyArr[i]] : null
};
};

export const noop = function noop(a?, b?) {
};
Loading

0 comments on commit c6d1d8e

Please sign in to comment.