介绍
本篇文章主要介绍基于json schema 实现 vue antd 的动态表单中的第三部分:实现。
介绍如何解析 json schema 和 ui schema 代码实现!
- 源码
- vue-alain
- vue antd 基于json schema 的动态表单实现 一: schema介绍
- vue antd 基于json schema 的动态表单实现 二: 动态表单使用
源代码实现
DyForm
动态表单的容器,主要负责解析 json shcema 和 uischema,以及提供表单项加载容器
提交
保存
DyFormitem
主要是动态表单项form-item
的展示容器,根据dy-form
组件中传递解析后的form属性进行表单渲染
dyformitemMixin
动态表单项和表单组件的混入,提炼每个组件需要的公共方法和属性
import { Observable, Subscription, BehaviorSubject } from 'rxjs';
import {
Component,
Prop,
Vue,
Emit,
Model,
Watch,
} from 'vue-property-decorator';
import { DFSchema } from './schema/DfSchema';
import FormProperty from './domain/FormProperty';
export interface IDyFormMixin {
formitem?: FormProperty;
}
/**
* 动态表单项组件的混入
*/
@Component({})
export default class DyFormMixin extends Vue implements IDyFormMixin {
/**
* 表单属性
*/
@Prop({type: Object, default: () => {}})
public formitem!: FormProperty;
/**
* 组件属性
*/
get widgetAttrs() {
return this.formitem.widgetAttrs;
}
/**
* form-item 属性
*/
get itemAttrs() {
return this.formitem.formitemAttrs;
}
/**
* 标签
*/
get label(): string {
return this.formitem.label;
}
}
StringWidget
文本框组件
其他动态表单的组件编写和
StringWidget
保持同样的代码,只不过是将a-input
转换为其他组件
WidgetRegistry
动态表单组件注册类, 提供注册和获取方法
import { Component, Prop, Vue } from 'vue-property-decorator';
/**
* 动态表单组件注册类
* 提供注册和获取方法
*/
class WidgetRegistry {
private widgets: { [type: string]: any } = {};
private defaultWidget: any;
/**
* 设置默认组件,以便找不到type对应的逐渐时候显示
* @param widget
*/
public setDefault(widget: any) {
this.defaultWidget = widget;
}
/**
* 注册动态表单组件
* @param type
* @param widget
*/
public register(type: string, widget: any) {
this.widgets[type] = widget;
}
/**
* 判断指定的组件名称是否存在
* @param type
*/
public has(type: string) {
return this.widgets.hasOwnProperty(type);
}
/**
* 根据指定类型获取动态组件
* @param type
*/
public getType(type: string): any {
if (this.has(type)) {
return this.widgets[type];
}
return this.defaultWidget;
}
}
const widgetRegistry = new WidgetRegistry();
export default widgetRegistry;
注册组件见代码
// 日期范围
registry.register('df-daterange', DateRangeWidget);
// 数字输入框
registry.register('df-number', NumberWidget);
// 文本框
registry.register('df-string', StringWidget);
registry.register('df-text', TextWidget);
// 区域文本框
registry.register('df-textarea', TextareaWidget);
// 开关
registry.register('df-boolean', SwitchWidget);
// 拖动条
registry.register('df-slider', SliderWidget);
// 星打分
registry.register('df-rate', RateWidget);
// 下拉框
registry.register('df-select', SelectWidget);
// 单选框
registry.register('df-radio', RadioWidget);
// 上传文件
registry.register('df-upload', UploadWidget);
registry.register('df-uploaddragger', UploadDraggerWidget);
FormProperty
form属性,主要是提供一些属性,提供给动态表单项属性,
一般是由json shcme 和ui shcmea组成
import { DFSchema } from './../schema/DfSchema';
import { DFUISchemaItem } from './../schema/UiSchema';
// tslint:disable:variable-name
/**
* form属性,主要是提供一些属性,提供给动态表单项属性
* 一般是有 json schem 和 ui shcem 和 formdata组合提供
*/
export default class FormProperty {
public formData: any = {};
private _formSchem: DFSchema = {};
private _uiSchema: DFUISchemaItem = {};
private _propertyId: string = '' ;
private _required: string[] = [];
constructor(
propertyId: string ,
formSchema: DFSchema,
uiSchema: DFUISchemaItem,
required: string[] = []) {
this._propertyId = propertyId;
this._formSchem = formSchema;
this._uiSchema = uiSchema;
this._required = required;
}
get key(): string {
return this._propertyId;
}
get id(): string {
return `$$${this._propertyId}`;
}
get formSchema(): DFSchema {
if (this._formSchem == null) {
return {};
}
return this._formSchem;
}
get uiSchema(): DFUISchemaItem {
const itemui: any = this.formSchema.ui;
const ui: any = this._uiSchema;
return {
...itemui,
...ui,
};
}
get type() {
if (this.uiSchema.widget) {
return this.uiSchema.widget;
}
return this.formSchema.type;
}
get formitemAttrs() {
const attrs = this.ui.itemattrs;
attrs.fieldDecoratorId = this.key;
attrs.fieldDecoratorOptions = this.fieldDecoratorOptions;
return attrs;
}
get widgetAttrs() {
return this.ui.widgetattrs;
}
get ui(): any {
const propertyUi: any = this.formSchema.ui;
const ui = {
...propertyUi,
...this.uiSchema,
};
return ui;
}
get label(): string {
if (this.formSchema.title) {
return this.formSchema.title;
}
if (this.uiSchema.widgetattrs && this.uiSchema.widgetattrs.label) {
return this.uiSchema.widgetattrs.label;
}
return this.key;
}
get listSource(): any[] {
if (!this.formSchema.enum) {
return [];
}
return this.formSchema.enum;
}
get rules(): any[] {
const rules: any[] = [];
const isRequired = this._required.includes(this.key);
if (isRequired) {
let msg = '必填项';
if (this.ui.errors) {
msg = this.ui.errors.required;
}
rules.push({ required: true, message: msg });
}
if (this.formSchema.maxLength) {
let msg = '超过最大长度';
if (this.ui.errors) {
msg = this.ui.errors.maxLength;
}
rules.push({ max: this.formSchema.maxLength, message: msg });
}
if (this.formSchema.minLength) {
let msg = '最小长度';
if (this.ui.errors) {
msg = this.ui.errors.minLength;
}
rules.push({ min: this.formSchema.minLength, message: msg });
}
if (this.formSchema.pattern) {
let msg = '正则表达式不正确';
if (this.ui.errors) {
msg = this.ui.errors.pattern;
}
rules.push({ pattern: this.formSchema.pattern, message: msg });
}
if (this.formSchema.maximum) {
let msg = '最大数';
if (this.ui.errors) {
msg = this.ui.errors.maximum;
}
rules.push({ type: 'number', max: this.formSchema.maximum, message: msg });
}
if (this.formSchema.minimum) {
let msg = '最小数';
if (this.ui.errors) {
msg = this.ui.errors.minimum;
}
rules.push({ type: 'number', min: this.formSchema.minimum, message: msg });
}
// { required: true, message: '请输入姓名' }
return rules;
}
get fieldDecoratorOptions(): any {
return {
initialValue: this.formData[this.key],
rules: this.rules,
};
}
}
参考资料
ng-alain-form
json shcema
antd-vue