Skip to content

Commit

Permalink
feat(vue3): 完成 vue3 form组件
Browse files Browse the repository at this point in the history
  • Loading branch information
lljj-x committed Jan 15, 2021
1 parent ab481d6 commit 1c5deba
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 147 deletions.
2 changes: 2 additions & 0 deletions packages/demo-v3/src/pages/index/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,5 @@ app.use(ElementPlus);

// mount
app.mount('#app');

window.app1 = app;
3 changes: 0 additions & 3 deletions packages/lib/utils/index.js

This file was deleted.

67 changes: 67 additions & 0 deletions packages/lib/utils/vue3Utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* Created by Liu.Jun on 2020/4/25 14:45.
*/

import { resolveComponent as _resolveComponent } from 'vue';

// 内部使用 . ,配置数据key不能出现.
const pathSeparator = '.';

// nodePath 转css类名
export function nodePath2ClassName(path) {
const rootPathName = '__pathRoot';
return path ? `${rootPathName}.${path}`.replace(/\./g, '_') : rootPathName;
}

// 是否为根节点
export function isRootNodePath(path) {
return path === '';
}

// 计算当前节点path
export function computedCurPath(prePath, curKey) {
return prePath === '' ? curKey : [prePath, curKey].join(pathSeparator);
}

// 删除当前path值
export function deletePathVal(vueData, name) {
// Vue.delete(vueData, name);
}

// 设置当前path值
export function setPathVal(obj, path, value) {
// Vue.set ?
const pathArr = path.split(pathSeparator);
for (let i = 0; i < pathArr.length; i += 1) {
if (pathArr.length - i < 2) {
// 倒数第一个数据
// obj[pathArr[pathArr.length - 1]] = value;
// Vue.set(obj, pathArr[pathArr.length - 1], value);
break;
}
obj = obj[pathArr[i]];
}
}

// 获取当前path值
export function getPathVal(obj, path, leftDeviation = 0) {
const pathArr = path.split(pathSeparator);

for (let i = 0; i < pathArr.length - leftDeviation; i += 1) {
// 错误路径或者undefined中断查找
if (obj === undefined) return undefined;
obj = pathArr[i] === '' ? obj : obj[pathArr[i]];
}
return obj;
}

// path 等于props
export function path2prop(path) {
return path;
}

export function resolveComponent(component) {
if (typeof component === 'string') return _resolveComponent(component);

return component;
}
43 changes: 22 additions & 21 deletions packages/lib/vue3-core/JsonSchemaForm/components/FormFooter.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
* Created by Liu.Jun on 2020/12/27 9:53 下午.
*/

import { h } from 'vue';

import { resolveComponent } from '@lljj/vjsf-utils/vue3Utils';

export default {
name: 'FormFooter',
props: {
Expand All @@ -13,38 +17,35 @@ export default {
type: String,
default: '取消'
},
globalOptions: null
globalOptions: {
type: Object,
default: () => ({})
}
},
render(h) {
const self = this;
const { okBtn, cancelBtn, globalOptions: { COMPONENT_MAP } } = this.$props;
emits: ['cancel', 'submit'],
setup(props, { emit }) {
// globalOptions 不需要响应式
const { globalOptions: { COMPONENT_MAP } } = props;

return h(COMPONENT_MAP.formItem, {
return () => h(COMPONENT_MAP.formItem, {
class: {
formFooter_item: true
}
}, [
h(COMPONENT_MAP.button, {
on: {
click() {
self.$emit('onCancel');
}
h(resolveComponent(COMPONENT_MAP.button), {
onClick() {
emit('cancel');
}
}, cancelBtn),
h(COMPONENT_MAP.button, {
}, props.cancelBtn),
h(resolveComponent(COMPONENT_MAP.button), {
style: {
marginLeft: '10px'
},
props: {
type: 'primary'
},
on: {
click() {
self.$emit('onSubmit');
}
type: 'primary',
onClick() {
emit('submit');
}
}, okBtn)
}, props.okBtn)
]);

}
};
187 changes: 64 additions & 123 deletions packages/lib/vue3-core/JsonSchemaForm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
getCurrentInstance, watch, ref, computed, h
} from 'vue';

import { resolveComponent } from '@lljj/vjsf-utils/vue3Utils';

// 生成form表单默认数据
import getDefaultFormState from '@lljj/vjsf-utils/schema/getDefaultFormState';
import { deepEquals } from '@lljj/vjsf-utils/utils';
Expand All @@ -18,13 +20,12 @@ import FormFooter from './components/FormFooter.js';
import SchemaField from './fields/SchemaField';

import './index.css';
import WIDGET_MAP from '@lljj/vue3-form-element/src/config/widgets/WIDGET_MAP';

export default function createForm(globalOptions = {}) {
const Form = {
name: 'VueElementForm',
props: vueProps,
emits: ['update:modelValue', 'change'],
emits: ['update:modelValue', 'change', 'cancel', 'submit', 'validation-failed'],
setup(props, ctx) {
// 注册组件
const internalInstance = getCurrentInstance();
Expand All @@ -41,6 +42,8 @@ export default function createForm(globalOptions = {}) {
...props.formFooter
}));

const formRef = ref(null);

// 更新formData
const emitFormDataChange = (newValue, oldValue) => {
// 支持v-model ,引用类型
Expand Down Expand Up @@ -86,138 +89,76 @@ export default function createForm(globalOptions = {}) {
const defaultSlot = ctx.slots.default
? ctx.slots.default({
formData,
formRefFn: () => ctx.$refs.genEditForm
formRefFn: () => formRef.value
})
: footerParams.value.show
? h(FormFooter, {
props: {
globalOptions,
okBtn: footerParams.okBtn,
cancelBtn: footerParams.cancelBtn,
globalOptions,
okBtn: footerParams.okBtn,
cancelBtn: footerParams.cancelBtn,
onCancel() {
ctx.emit('cancel');
},
on: {
onCancel() {
ctx.emit('cancel');
},
onSubmit() {
ctx.$refs.genEditForm.validate((isValid, resData) => {
if (isValid) {
return ctx.emit('on-submit', formData);
}
console.warn(resData);
return ctx.emit('on-validation-failed', resData);
});
}
onSubmit() {
formRef.value.validate((isValid, resData) => {
if (isValid) {
return ctx.emit('submit', formData);
}
console.warn(resData);
return ctx.emit('validation-failed', resData);
});
}
}) : null;

return () => 'Vue3 嘿嘿嘿';
const { layoutColumn = 1, ...formProps } = props.formProps;

const schemaProps = {
schema: props.schema,
uiSchema: props.uiSchema,
errorSchema: props.errorSchema,
customFormats: props.customFormats,
customRule: props.customRule,
rootSchema: props.schema,
rootFormData: formData.value, // 根节点的数据
curNodePath: '', // 当前节点路径
globalOptions, // 全局配置,差异化ui框架
formProps: {
labelPosition: 'top',
labelSuffix: ':',
...formProps,
}
};

return () => h(
resolveComponent(globalOptions.COMPONENT_MAP.form),
{
class: {
genFromComponent: true,
[`formLabel-${schemaProps.formProps.labelPosition}`]: true,
formInlineFooter: formProps.inlineFooter,
formInline: formProps.inline,
[`genFromComponent_${props.schema.id}Form`]: !!props.schema.id,
layoutColumn: !formProps.inline,
[`layoutColumn-${layoutColumn}`]: !formProps.inline
},
ref: formRef,
model: formData,
...schemaProps.formProps
},
[
h(
SchemaField,
{
...schemaProps
}
),
defaultSlot,
]
);
},
// 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);
// if (!deepEquals(this.formData, formData)) {
// this.formData = formData;
// }
// }
// },
// },
// render(h) {
// const self = this;
// // default scoped slot
// const defaultSlot = this.$scopedSlots.default
// ? this.$scopedSlots.default({
// formData: self.formData,
// formRefFn: () => self.$refs.genVueForm
// })
// : this.footerParams.show
// ? h(FormFooter, {
// props: {
// globalOptions,
// okBtn: self.footerParams.okBtn,
// cancelBtn: self.footerParams.cancelBtn,
// },
// on: {
// onCancel() {
// self.$emit('on-cancel');
// },
// onSubmit() {
// self.$refs.genVueForm.validate((isValid, resData) => {
// if (isValid) {
// return self.$emit('on-submit', self.formData);
// }
// console.warn(resData);
// return self.$emit('on-validation-failed', resData);
// });
// }
// }
// }) : undefined;
//
// const { layoutColumn = 1, ...formProps } = self.$props.formProps;
//
// 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: 'top',
// labelSuffix: ':',
// ...formProps,
// }
// };
//
// return h(
// globalOptions.COMPONENT_MAP.form,
// {
// class: {
// genFromComponent: true,
// [`formLabel-${props.formProps.labelPosition}`]: true,
// formInlineFooter: formProps.inlineFooter,
// formInline: formProps.inline,
// [`genFromComponent_${this.schema.id}Form`]: !!this.schema.id,
// layoutColumn: !formProps.inline,
// [`layoutColumn-${layoutColumn}`]: !formProps.inline
// },
// ref: 'genVueForm',
// props: {
// model: self.formData,
// ...props.formProps
// }
// },
// [
// h(
// SchemaField,
// {
// props
// }
// ),
// defaultSlot,
// ]
// );
// }
};

Form.install = (vueApp, options = {}) => {
debugger;
vueApp.component(Form.name || options.name, Form);
};

Expand Down

0 comments on commit 1c5deba

Please sign in to comment.