248 lines
6.7 KiB
JavaScript
248 lines
6.7 KiB
JavaScript
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["update:modelValue"] = (val) => {
|
||
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];
|
||
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);
|
||
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 (
|
||
<>
|
||
{children.length > 0 ? (
|
||
<Tag
|
||
{...dataObject.attrs}
|
||
on={dataObject.on}
|
||
modelValue={this.$props.conf.__config__.defaultValue}
|
||
>
|
||
{children}
|
||
</Tag>
|
||
) : (
|
||
<Tag
|
||
{...dataObject.attrs}
|
||
on={dataObject.on}
|
||
modelValue={this.$props.conf.__config__.defaultValue}
|
||
></Tag>
|
||
)}
|
||
</>
|
||
);
|
||
},
|
||
});
|