UNPKG

@visactor/vue-vtable

Version:
120 lines (117 loc) 5.49 kB
import * as VTable from '@visactor/vtable'; import { convertPropsToCamelCase, toCamelCase } from './stringUtils.js'; import { isObject, isNil, isFunction } from '@visactor/vutils'; import { isVNode, cloneVNode } from 'vue'; // 检查属性是否为事件 function isEventProp(key, props) { return key.startsWith('on') && isFunction(props[key]); } // 创建自定义布局 function createCustomLayout(children, isHeader, args) { // 同一 cell 内多个 vue Group 的计数器,每次 createCustomLayout 调用时归零 let vueIndex = 0; // 组件映射 const componentMap = { Group: VTable.CustomLayout.Group, Image: VTable.CustomLayout.Image, Text: VTable.CustomLayout.Text, Tag: VTable.CustomLayout.Tag, Radio: VTable.CustomLayout.Radio, CheckBox: VTable.CustomLayout.CheckBox }; // 创建组件的函数 function createComponent(child) { var _a, _b; if (!child) { return null; } const { type, children: childChildren } = child; const props = convertPropsToCamelCase(child.props); const componentName = (type === null || type === void 0 ? void 0 : type.symbol) || (type === null || type === void 0 ? void 0 : type.name); const ComponentClass = componentMap[componentName]; if (!ComponentClass) { return null; } // 创建组件实例 const component = new ComponentClass(Object.assign({}, props)); // 绑定组件事件 bindComponentEvents(component, props); // 递归创建子组件 const subChildren = resolveChildren(childChildren); if (isObject(props === null || props === void 0 ? void 0 : props.vue)) { // vue 自定义节点:无需继续循环子节点 const { element } = props.vue; let targetVNode = element !== null && element !== void 0 ? element : subChildren.find(node => (node === null || node === void 0 ? void 0 : node.type) !== Symbol.for('v-cmt')); if (isVNode(targetVNode)) { // node 标记 key 增加唯一项标记,避免重复渲染 targetVNode = !targetVNode.key ? cloneVNode(targetVNode, { key: `row_${args.row}_col_${args.col}` }) : targetVNode; } else { targetVNode = null; } // 注入稳定 ID:基于 cell 坐标 + 递增索引,确保场景图重建后缓存 key 不变 const stableId = isNil(props.vue.id) ? `cell_${args.col}_${args.row}_${vueIndex++}` : undefined; Object.assign(child.props.vue, Object.assign({ element: targetVNode, // 不接入外部指定 container: isHeader ? (_a = args === null || args === void 0 ? void 0 : args.table) === null || _a === void 0 ? void 0 : _a.headerDomContainer : (_b = args === null || args === void 0 ? void 0 : args.table) === null || _b === void 0 ? void 0 : _b.bodyDomContainer }, (stableId ? { id: stableId } : {}))); return component; } subChildren.forEach((subChild) => { const subComponent = createComponent(subChild); if (subComponent) { component.add(subComponent); } else if (subChild.type === Symbol.for('v-fgt')) { subChild.children.forEach((nestedChild) => { const nestedComponent = createComponent(nestedChild); if (nestedComponent) { component.add(nestedComponent); } }); } }); return component; } // 处理子节点 function resolveChildren(childChildren) { var _a; return ((_a = childChildren === null || childChildren === void 0 ? void 0 : childChildren.default) === null || _a === void 0 ? void 0 : _a.call(childChildren)) || childChildren || []; } // 绑定组件事件 function bindComponentEvents(component, props) { Object.keys(props).forEach(key => { if (isEventProp(key, props)) { let eventName; if (key.startsWith('on')) { eventName = key.slice(2).toLowerCase(); // 去掉'on'前缀并转换为小写 } else { eventName = toCamelCase(key.slice(2)).toLowerCase(); // 转换为camelCase } component.addEventListener(eventName, props[key]); } }); } // 返回root组件和refs return { rootComponent: createComponent(children) }; } function createCustomLayoutHandler(children, isHeader) { return (args) => { const { table, row, col, rect } = args; const record = table.getCellOriginRecord(col, row); const { height, width } = rect !== null && rect !== void 0 ? rect : table.getCellRect(col, row); const customLayoutKey = isHeader ? 'headerCustomLayout' : 'customLayout'; if (!children[customLayoutKey]) { return null; } const rootContainer = children[customLayoutKey]({ table, row, col, rect, record, height, width })[0]; const { rootComponent } = createCustomLayout(rootContainer, isHeader, args); return { rootContainer: rootComponent, renderDefault: false }; }; } export { createCustomLayout, createCustomLayoutHandler };