form generator
This commit is contained in:
331
src/utils/generator/render.jsx
Normal file
331
src/utils/generator/render.jsx
Normal file
@ -0,0 +1,331 @@
|
||||
import { deepClone } from "@/utils/index";
|
||||
import {
|
||||
ElRow,
|
||||
ElRate,
|
||||
ElInput,
|
||||
ElSlider,
|
||||
ElSelect,
|
||||
ElButton,
|
||||
ElSwitch,
|
||||
ElUpload,
|
||||
ElCascader,
|
||||
ElDatePicker,
|
||||
ElTimePicker,
|
||||
ElRadioGroup,
|
||||
ElColorPicker,
|
||||
ElInputNumber,
|
||||
ElCheckboxGroup,
|
||||
} from "element-plus";
|
||||
// import Editor from "@/components/Editor";
|
||||
import { h, defineComponent } from "vue";
|
||||
|
||||
const formComponentsMap = {
|
||||
"el-row": ElRow,
|
||||
"el-rate": ElRate,
|
||||
"el-input": ElInput,
|
||||
"el-switch": ElSwitch,
|
||||
"el-select": ElSelect,
|
||||
"el-upload": ElUpload,
|
||||
"el-button": ElButton,
|
||||
"el-slider": ElSlider,
|
||||
"el-cascader": ElCascader,
|
||||
"el-time-picker": ElTimePicker,
|
||||
"el-radio-group": ElRadioGroup,
|
||||
"el-date-picker": ElDatePicker,
|
||||
"el-input-number": ElInputNumber,
|
||||
"el-color-picker": ElColorPicker,
|
||||
"el-checkbox-group": ElCheckboxGroup,
|
||||
// editor: Editor,
|
||||
};
|
||||
|
||||
const componentChild = {};
|
||||
/**
|
||||
* 将./slots中的文件挂载到对象componentChild上
|
||||
* 文件名为key,对应JSON配置中的__config__.tag
|
||||
* 文件内容为value,解析JSON配置中的__slot__
|
||||
*/
|
||||
const slotsFiles = import.meta.glob("./slots/*.jsx", { eager: true });
|
||||
// const slotsFiles = require.context("./slots", false, /\.js$/);
|
||||
const keys = Object.keys(slotsFiles) || [];
|
||||
keys.forEach((key) => {
|
||||
const tag = key.replace(/^\.\/slots\/(.*)\.\w+$/, "$1");
|
||||
componentChild[tag] = slotsFiles[key].default;
|
||||
});
|
||||
|
||||
function vModel(dataObject, defaultValue) {
|
||||
dataObject.props.value = defaultValue;
|
||||
dataObject.on.input = (val) => {
|
||||
this.$emit("input", val);
|
||||
};
|
||||
dataObject.on.change = (val) => {
|
||||
console.log(val, "change");
|
||||
this.$emit("input", val);
|
||||
};
|
||||
}
|
||||
|
||||
function mountSlotFiles(confClone, children) {
|
||||
const childObjs = componentChild[confClone.__config__.tag];
|
||||
if (childObjs) {
|
||||
Object.keys(childObjs).forEach((key) => {
|
||||
const childFunc = childObjs[key];
|
||||
console.log(childFunc);
|
||||
if (confClone.__slot__ && confClone.__slot__[key]) {
|
||||
children.push(childFunc(confClone, key));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function emitEvents(confClone) {
|
||||
["on", "nativeOn"].forEach((attr) => {
|
||||
const eventKeyList = Object.keys(confClone[attr] || {});
|
||||
eventKeyList.forEach((key) => {
|
||||
const val = confClone[attr][key];
|
||||
if (typeof val === "string") {
|
||||
confClone[attr][key] = (event) => this.$emit(val, event);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function buildDataObject(confClone, dataObject) {
|
||||
Object.keys(confClone).forEach((key) => {
|
||||
const val = confClone[key];
|
||||
if (key === "__vModel__") {
|
||||
vModel.call(this, dataObject, confClone.__config__.defaultValue);
|
||||
} else if (dataObject[key] !== undefined) {
|
||||
if (
|
||||
dataObject[key] === null ||
|
||||
dataObject[key] instanceof RegExp ||
|
||||
["boolean", "string", "number", "function"].includes(
|
||||
typeof dataObject[key]
|
||||
)
|
||||
) {
|
||||
dataObject[key] = val;
|
||||
} else if (Array.isArray(dataObject[key])) {
|
||||
dataObject[key] = [...dataObject[key], ...val];
|
||||
} else {
|
||||
dataObject[key] = { ...dataObject[key], ...val };
|
||||
}
|
||||
} else {
|
||||
dataObject.attrs[key] = val;
|
||||
}
|
||||
});
|
||||
|
||||
// 清理属性
|
||||
clearAttrs(dataObject);
|
||||
}
|
||||
|
||||
function clearAttrs(dataObject) {
|
||||
delete dataObject.attrs.__config__;
|
||||
delete dataObject.attrs.__slot__;
|
||||
delete dataObject.attrs.__methods__;
|
||||
}
|
||||
|
||||
function makeDataObject() {
|
||||
// 深入数据对象:
|
||||
// https://cn.vuejs.org/v2/guide/render-function.html#%E6%B7%B1%E5%85%A5%E6%95%B0%E6%8D%AE%E5%AF%B9%E8%B1%A1
|
||||
return {
|
||||
class: {},
|
||||
attrs: {},
|
||||
props: {},
|
||||
domProps: {},
|
||||
nativeOn: {},
|
||||
on: {},
|
||||
style: {},
|
||||
directives: [],
|
||||
scopedSlots: {},
|
||||
slot: null,
|
||||
key: null,
|
||||
ref: null,
|
||||
refInFor: true,
|
||||
};
|
||||
}
|
||||
|
||||
// export default defineComponent({
|
||||
// name: "render",
|
||||
// props: {
|
||||
// conf: {
|
||||
// type: Object,
|
||||
// required: true,
|
||||
// },
|
||||
// },
|
||||
// setup(props, ctx) {
|
||||
// console.log(props);
|
||||
// console.log(ctx);
|
||||
// const dataObject = makeDataObject();
|
||||
// const confClone = deepClone(props.conf);
|
||||
// const children = [ctx.slots.default] || [];
|
||||
// // 如果slots文件夹存在与当前tag同名的文件,则执行文件中的代码
|
||||
// mountSlotFiles.call(this, h, confClone, children);
|
||||
|
||||
// // 将字符串类型的事件,发送为消息
|
||||
// emitEvents.call(this, confClone);
|
||||
|
||||
// // 将json表单配置转化为vue render可以识别的 “数据对象(dataObject)”
|
||||
// buildDataObject.call(this, confClone, dataObject);
|
||||
// const Tag = props.conf.__config__.tag;
|
||||
// return <Tag></Tag>;
|
||||
// },
|
||||
// });
|
||||
|
||||
export default defineComponent({
|
||||
name: "render",
|
||||
props: {
|
||||
conf: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
arr: [],
|
||||
tempTime: "",
|
||||
};
|
||||
},
|
||||
emits: ["input"],
|
||||
// setup(props, { slots, emit }) {
|
||||
// const dataObject = makeDataObject();
|
||||
// const confClone = deepClone(props.conf);
|
||||
// // const children = [this.$slots.default] || [];
|
||||
// console.log(slots, "slots");
|
||||
// const children = [];
|
||||
// // 如果slots文件夹存在与当前tag同名的文件,则执行文件中的代码
|
||||
// mountSlotFiles(h, confClone, children);
|
||||
|
||||
// // 将字符串类型的事件,发送为消息
|
||||
// emitEvents(emit, confClone);
|
||||
// setTimeout(() => {
|
||||
// emit("input", "4ww3243");
|
||||
// }, 3000);
|
||||
// // 将json表单配置转化为vue render可以识别的 “数据对象(dataObject)”
|
||||
// const update = (val) => {
|
||||
// console.log(val, "update");
|
||||
// emit("input", val);
|
||||
// };
|
||||
// buildDataObject(update, confClone, dataObject);
|
||||
|
||||
// const Tag = formComponentsMap[props.conf.__config__.tag];
|
||||
|
||||
// return () => (
|
||||
// <Tag
|
||||
// {...dataObject.attrs}
|
||||
// on={dataObject.on}
|
||||
// modelValue={confClone.__config__.defaultValue}
|
||||
// >
|
||||
// {children}
|
||||
// </Tag>
|
||||
// );
|
||||
// },
|
||||
render() {
|
||||
const dataObject = makeDataObject();
|
||||
const confClone = deepClone(this.$props.conf);
|
||||
console.log(this.$slots.default, "lot");
|
||||
const children = [];
|
||||
// 如果slots文件夹存在与当前tag同名的文件,则执行文件中的代码
|
||||
mountSlotFiles(confClone, children);
|
||||
// 将字符串类型的事件,发送为消息
|
||||
emitEvents.call(this, confClone);
|
||||
|
||||
// 将json表单配置转化为vue render可以识别的 “数据对象(dataObject)”
|
||||
buildDataObject.call(this, confClone, dataObject);
|
||||
const Tag = formComponentsMap[this.$props.conf.__config__.tag];
|
||||
|
||||
// return h(Tag, dataObject.attrs, children);
|
||||
return (
|
||||
<>
|
||||
{children.length > 0 ? (
|
||||
<Tag
|
||||
{...dataObject.attrs}
|
||||
on={dataObject.on}
|
||||
v-model={this.$props.conf.__config__.defaultValue}
|
||||
>
|
||||
{children}
|
||||
</Tag>
|
||||
) : (
|
||||
<Tag
|
||||
{...dataObject.attrs}
|
||||
on={dataObject.on}
|
||||
v-model={this.$props.conf.__config__.defaultValue}
|
||||
></Tag>
|
||||
)}
|
||||
</>
|
||||
|
||||
// <Tag options={dataObject.attrs.options} />
|
||||
);
|
||||
},
|
||||
// render() {
|
||||
|
||||
// return (
|
||||
// <>
|
||||
// {tag == "el-input" ? (
|
||||
// <el-input
|
||||
// {...dataObject.attrs}
|
||||
// on={dataObject.on}
|
||||
// modelValue={confClone.__config__.defaultValue}
|
||||
// >
|
||||
// {children}
|
||||
// </el-input>
|
||||
// ) : tag == "el-input-number" ? (
|
||||
// <el-input-number
|
||||
// {...dataObject.attrs}
|
||||
// on={dataObject.on}
|
||||
// modelValue={confClone.__config__.defaultValue}
|
||||
// >
|
||||
// {children}
|
||||
// </el-input-number>
|
||||
// ) : tag == "el-slider" ? (
|
||||
// <el-slider
|
||||
// {...dataObject.attrs}
|
||||
// on={dataObject.on}
|
||||
// modelValue={confClone.__config__.defaultValue}
|
||||
// >
|
||||
// {children}
|
||||
// </el-slider>
|
||||
// ) : tag == "el-time-picker" ? (
|
||||
// <el-date-picker
|
||||
// type="datetimerange"
|
||||
// on={dataObject.on}
|
||||
// modelValue={confClone.__config__.defaultValue}
|
||||
// />
|
||||
// ) : tag === "el-switch" ? (
|
||||
// <el-switch
|
||||
// {...dataObject.attrs}
|
||||
// on={dataObject.on}
|
||||
// modelValue={confClone.__config__.defaultValue}
|
||||
// ></el-switch>
|
||||
// ) : tag === "el-color-picker" ? (
|
||||
// <el-color-picker
|
||||
// {...dataObject.attrs}
|
||||
// on={dataObject.on}
|
||||
// modelValue={confClone.__config__.defaultValue}
|
||||
// ></el-color-picker>
|
||||
// ) : tag === "el-button" ? (
|
||||
// <el-button
|
||||
// {...dataObject.attrs}
|
||||
// on={dataObject.on}
|
||||
// modelValue={confClone.__config__.defaultValue}
|
||||
// >
|
||||
// {children[1]}
|
||||
// </el-button>
|
||||
// ) : tag === "el-select" ? (
|
||||
// <el-select
|
||||
// {...dataObject.attrs}
|
||||
// on={dataObject.on}
|
||||
// modelValue={confClone.__config__.defaultValue}
|
||||
// >
|
||||
// {children}
|
||||
// </el-select>
|
||||
// ) : tag === "el-date-picker" ? (
|
||||
// <el-date-picker
|
||||
// {...dataObject.attrs}
|
||||
// on={dataObject.on}
|
||||
// modelValue={confClone.__config__.defaultValue}
|
||||
// >
|
||||
// {children}
|
||||
// </el-date-picker>
|
||||
// ) : null}
|
||||
// </>
|
||||
// );
|
||||
// },
|
||||
});
|
Reference in New Issue
Block a user