/* eslint-disable no-unused-vars */ import Vue from 'vue'; import { PropType, CreateElement, VNode, VNodeChildren, RenderContext, } from 'vue/types/umd'; import { ScopedSlotReturnValue } from 'vue/types/vnode'; import { LNode } from '../common.type'; // 组件render属性的ts类型 type RenderTsTypesSimple = string | number | boolean; type RenderTsTypesObject = Record | Array; type RenderTsTypes = VNode | VNodeChildren | LNode | RenderTsTypesSimple | RenderTsTypesObject; // 组件render属性的js类型 const RenderJsTypes = [Function, String, Number, Boolean, Object, Array]; enum RenderWay { Text = 'text', JsonString = 'jsonstring', VNode = 'vnode', Unknown = 'unknown', } export type VmType = Vue; const getValueRenderWay = (value: RenderTsTypes): RenderWay => { if (['string', 'number', 'boolean'].includes(typeof value)) return RenderWay.Text; if (typeof value === 'object') { // 虚拟dom对象 if (!(value instanceof Array) && value && value.context instanceof Vue) { return RenderWay.VNode; } // 其他复杂对象或数组 return RenderWay.JsonString; } // 未知类型 return RenderWay.Unknown; }; export const RenderLNodeTemplate = Vue.extend({ name: 'render-lnode-template', functional: true, props: { render: RenderJsTypes as PropType, params: null as PropType, }, render(h: CreateElement, ctx: RenderContext): VNode { const { render, params } = ctx.props; const renderResult = typeof render === 'function' ? render(h, params) : render; const renderWay = getValueRenderWay(renderResult); // @ts-ignore const renderText = (c: RenderTsTypesSimple | RenderTsTypesObject) => ctx.__proto__._v(c); const renderMap = { [RenderWay.Text]: (c: RenderTsTypesSimple) => renderText(c), [RenderWay.JsonString]: (c: RenderTsTypesObject) => renderText(JSON.stringify(c, null, 2)), [RenderWay.VNode]: (c: VNode) => c, }; return renderMap[renderWay] ? renderMap[renderWay](renderResult) : h(); }, }); interface JSXRenderContext { defaultNode?: VNode; params?: Record; // 是否不打印 LOG silent?: boolean; } export const renderLNodeJSX = (vm: VmType, name: string, options?: ScopedSlotReturnValue | JSXRenderContext) => { const params = typeof options === 'object' && 'params' in options ? options.params : null; const defaultNode = typeof options === 'object' && 'defaultNode' in options ? options.defaultNode : options; const propsNode = vm[name]; if (propsNode === false) return; if (propsNode === true && defaultNode) { return vm.$scopedSlots[name] ? vm.$scopedSlots[name](params) : defaultNode; } if (typeof propsNode === 'function') return propsNode(vm.$createElement, params); const isPropsEmpty = [undefined, params, ''].includes(propsNode); if (isPropsEmpty && vm.$scopedSlots[name]) return vm.$scopedSlots[name](params); return propsNode; }; export const renderLNodeJSXDefault = (vm: VmType, name: string, options?: ScopedSlotReturnValue | JSXRenderContext) => { const defaultNode = typeof options === 'object' && 'defaultNode' in options ? options.defaultNode : options; return renderLNodeJSX(vm, name, options) || defaultNode; }; export const renderContent = (vm: VmType, name1: string, name2: string, options?: VNode | JSXRenderContext) => { const params = typeof options === 'object' && 'params' in options ? options.params : null; let defaultNode = typeof options === 'object' && 'defaultNode' in options && options.defaultNode; defaultNode = typeof options === 'object' && 'context' in options && options; const toParams = params ? { params } : undefined; const node1 = renderLNodeJSX(vm, name1, toParams); const node2 = renderLNodeJSX(vm, name2, toParams); const r = [undefined, null, ''].includes(node1) ? node2 : node1; return [undefined, null, ''].includes(r) ? defaultNode : r; };