@lljj/vue2-form-core
Version:
基于 Vue 、JsonSchema快速构建一个带完整校验的form表单,vue2版本基础框架
206 lines (185 loc) • 7.04 kB
JavaScript
/**
* Created by Liu.Jun on 2020/4/16 17:32.
*/
import Vue from 'vue';
// 生成form表单默认数据
import getDefaultFormState from '@lljj/vjsf-utils/schema/getDefaultFormState';
import { deepEquals } from '@lljj/vjsf-utils/utils';
// 基础公共样式
import '@lljj/vjsf-utils/style/baseForm.css';
import vueProps from './props';
// 默认表单底部
import FormFooter from './components/FormFooter.js';
import SchemaField from './fields/SchemaField';
import fieldProps from './fields/props';
export {
fieldProps,
SchemaField
};
export default function createForm(globalOptions = {}) {
// global components
if (globalOptions.WIDGET_MAP.widgetComponents) {
Object.entries(globalOptions.WIDGET_MAP.widgetComponents).forEach(([key, value]) => Vue.component(key, value));
}
return {
name: 'VueForm',
props: vueProps,
provide() {
return {
genFormProvide: this.genFormProvide
};
},
data() {
const formData = getDefaultFormState(this.$props.schema, this.$props.value, this.$props.schema, this.$props.strictMode);
// 保持v-model双向数据及时性
this.emitFormDataChange(formData, this.value);
return {
formData
};
},
computed: {
genFormProvide() {
return this.$props;
},
footerParams() {
return {
show: true,
okBtn: '保存',
cancelBtn: '取消',
...this.formFooter
};
}
},
watch: {
formData: {
handler(newValue, oldValue) {
this.emitFormDataChange(newValue, oldValue);
},
deep: true
},
// 用于初始化了formData,监听变更是否重新计算 formData
schema(newVal, oldVal) {
this.willReceiveProps(newVal, oldVal);
},
value(newVal, oldVal) {
this.willReceiveProps(newVal, oldVal);
}
},
methods: {
emitFormDataChange(newValue, oldValue) {
// 支持v-model ,引用类型
this.$emit('input', newValue);
// change 事件,引用类型修改属性 newValue
this.$emit('on-change', {
newValue,
oldValue
});
},
// 避免用于双向绑定v-model 可能导致的循环调用
willReceiveProps(newVal, oldVal) {
if (!deepEquals(newVal, oldVal)) {
const formData = getDefaultFormState(this.$props.schema, this.$props.value, this.$props.schema, this.$props.strictMode);
if (!deepEquals(this.formData, formData)) {
this.formData = formData;
}
}
},
},
mounted() {
this.$$uiFormRef = this.$refs.genEditForm;
this.$emit('on-form-mounted', this.$refs.genEditForm, {
formData: this.formData
});
},
render(h) {
const self = this;
// default scoped slot
const defaultSlot = this.$scopedSlots.default
? this.$scopedSlots.default({
formData: self.formData,
formRefFn: () => self.$refs.genEditForm
})
: this.footerParams.show
? h(FormFooter, {
props: {
globalOptions,
okBtn: self.footerParams.okBtn,
okBtnProps: self.footerParams.okBtnProps,
cancelBtn: self.footerParams.cancelBtn,
formItemAttrs: self.footerParams.formItemAttrs,
},
on: {
onCancel() {
self.$emit('on-cancel');
},
onSubmit() {
self.$refs.genEditForm.validate((isValid, resData) => {
if (isValid) {
return self.$emit('on-submit', self.formData);
}
console.warn(resData);
return self.$emit('on-validation-failed', resData);
});
}
}
}) : undefined;
const {
// eslint-disable-next-line no-unused-vars
layoutColumn = 1, inlineFooter, labelSuffix, isMiniDes, defaultSelectFirstOption, popover, ...uiFormProps
} = self.$props.formProps;
const { inline = false, labelPosition = 'top' } = uiFormProps;
const props = {
schema: this.schema,
uiSchema: this.uiSchema,
errorSchema: this.errorSchema,
customFormats: this.customFormats,
customRule: this.customRule,
rootSchema: this.schema,
rootFormData: this.formData, // 根节点的数据
curNodePath: '', // 当前节点路径
globalOptions, // 全局配置,差异化ui框架
formProps: {
labelPosition,
labelSuffix: ':',
defaultSelectFirstOption: true,
inline,
...self.$props.formProps
}
};
return h(
globalOptions.COMPONENT_MAP.form,
{
class: {
genFromComponent: true,
formInlineFooter: inlineFooter,
formInline: inline,
[`genFromComponent_${this.schema.id}Form`]: !!this.schema.id,
layoutColumn: !inline,
[`layoutColumn-${layoutColumn}`]: !inline
},
nativeOn: {
submit(e) {
e.preventDefault();
}
},
ref: 'genEditForm',
props: {
model: self.formData,
labelPosition,
inline,
...uiFormProps
}
},
[
h(
SchemaField,
{
props
}
),
defaultSlot,
]
);
}
};
}