import { h, resolveComponent, toRaw, VNode } from "vue"; import { isObject } from "./index"; import { parseExtensionComponent } from "./parse"; import global from "./global"; import { useConfig } from "../hooks"; import { isFunction, isString } from "lodash-es"; // 配置 interface Options { // 标识 prop?: string; // 数据值 scope?: any; // 当前行 item?: any; // 插槽 slots?: any; // 子集 children?: any[] & any; // 自定义 custom?: (vnode: any) => any; // 渲染方式 render?: "slot" | null; // 其他 [key: string]: any; } // 临时注册组件列表 const regs: Map = new Map(); // 解析节点 export function parseNode(vnode: any, options: Options): VNode { const { scope, prop, slots, children, _data } = options || []; // 渲染后组件 let comp: VNode | null = null; // 插槽模式渲染 if (vnode.name?.includes("slot-")) { const rn = slots[vnode.name]; if (rn) { return rn({ scope, prop, ..._data }); } else { return ; } } // 实例模式下,先注册到全局,再分解组件渲染 if (vnode.vm && !regs.get(vnode.name)) { global.vue.component(vnode.name, { ...vnode.vm }); regs.set(vnode.name, { ...vnode.vm }); } // 处理 props if (isFunction(vnode.props)) { vnode.props = vnode.props({ scope, prop, ..._data }); } // 组件参数 const props = { ...vnode.props, ..._data, prop, scope }; // 是否禁用 props.disabled = _data?.isDisabled || props.disabled; // 添加双向绑定 if (props && scope) { if (prop) { props.modelValue = scope[prop]; props["onUpdate:modelValue"] = function (val: any) { scope[prop] = val; }; } } // 组件实例渲染 if (vnode.vm) { comp = h(regs.get(vnode.name), props); } else { const slots = { ...vnode.slots }; if (children) { slots.default = () => children; } // 渲染组件 comp = h(toRaw(resolveComponent(vnode.name)), props, slots); } // 挂载到 refs 中 if (isFunction(vnode.ref)) { setTimeout(() => { vnode.ref(comp?.component?.exposed); }, 0); } return comp; } // 渲染节点 export function renderNode(vnode: any, options: Options) { const config = useConfig(); const { item, scope, children, _data, render } = options || {}; if (!vnode) { return null; } if (vnode.__v_isVNode) { return vnode; } // 默认参数配置 if (item) { if (item.component) { if (!item.component.props) { item.component.props = {}; } // 占位符 let placeholder = ""; switch (item.component?.name) { case "el-select": placeholder = config.dict.label.placeholderSelect; break; default: placeholder = config.dict.label.placeholder; break; } if (placeholder) { if (!item.component.props.placeholder) { item.component.props.placeholder = placeholder + (item.label || ''); } } } } // 组件实例 if (vnode.vm) { if (!vnode.name) { vnode.name = vnode.vm?.name || vnode.vm?.__hmrId; } return parseNode(vnode, options); } // 组件名渲染 if (isString(vnode)) { if (render == "slot") { if (!vnode.includes("slot-")) { return vnode; } } return parseNode({ name: vnode }, options); } // 方法回调 if (isFunction(vnode)) { return vnode({ scope, h, ..._data }); } // jsx 模式 if (isObject(vnode)) { if (vnode.name) { return parseNode(vnode, { ...options, children, ...parseExtensionComponent(vnode) }); } else { if (options.custom) { return options.custom(vnode); } return ; } } }