vxe-table
Version:
A PC-end table component based on Vxe UI, supporting copy-paste, data pivot table, and high-performance virtual list table solution.
1,099 lines • 665 kB
JavaScript
import { h, reactive, ref, provide, inject, nextTick, Teleport, onActivated, onDeactivated, onBeforeUnmount, onUnmounted, watch, computed, onMounted } from 'vue';
import { defineVxeComponent } from '../../ui/src/comp';
import XEUtils from 'xe-utils';
import { initTpImg, getTpImg, isPx, isScale, hasClass, addClass, removeClass, scrollTopTo, getEventTargetNode, getPaddingTopBottomSize, setScrollTop, setScrollLeft, toCssUnit, hasControlKey, checkTargetElement } from '../../ui/src/dom';
import { getLastZIndex, nextZIndex, hasChildrenList, getFuncText, isEnableConf, formatText, eqEmptyValue } from '../../ui/src/utils';
import { VxeUI } from '../../ui';
import { createReactData, createInternalData, getRowUniqueId, createRowId, clearTableAllStatus, getColumnList, toFilters, hasDeepKey, getRowkey, getRowid, rowToVisible, colToVisible, getCellValue, setCellValue, handleRowidOrRow, handleFieldOrColumn, toTreePathSeq, restoreScrollLocation, getRootColumn, getRefElem, getColReMinWidth, createHandleUpdateRowId, createHandleGetRowId, getCalcHeight, getCellRestHeight, getLastChildColumn } from './util';
import { getSlotVNs } from '../../ui/src/vn';
import { moveRowAnimateToTb, clearRowAnimate, moveColAnimateToLr, clearColAnimate } from '../../ui/src/anime';
import { warnLog, errLog } from '../../ui/src/log';
import { getCrossTableDragRowInfo } from './store';
import Cell from './cell';
import TableBodyComponent from './body';
import TableHeaderComponent from './header';
import TableFooterComponent from './footer';
import { tableProps } from './props';
import { tableEmits } from './emits';
import TableCustomPanelComponent from '../module/custom/panel';
import TableFilterPanelComponent from '../module/filter/panel';
import TableImportPanelComponent from '../module/export/import-panel';
import TableExportPanelComponent from '../module/export/export-panel';
import TableMenuPanelComponent from '../module/menu/panel';
import '../module/filter/hook';
import '../module/menu/hook';
import '../module/edit/hook';
import '../module/export/hook';
import '../module/keyboard/hook';
import '../module/validator/hook';
import '../module/custom/hook';
import '../render';
const { getConfig, getIcon, getI18n, renderer, formats, createEvent, globalResize, interceptor, hooks, globalEvents, GLOBAL_EVENT_KEYS, useFns, renderEmptyElement } = VxeUI;
const supportMaxRow = 5e6;
const customStorageKey = 'VXE_CUSTOM_STORE';
const maxYHeight = 5e6;
const maxXWidth = 5e6;
const sourceType = 'table';
let crossTableDragRowObj = null;
export default defineVxeComponent({
name: 'VxeTable',
props: tableProps,
emits: tableEmits,
setup(props, context) {
const { slots, emit } = context;
const xID = XEUtils.uniqueId();
const browseObj = XEUtils.browse();
// 使用已安装的组件,如果未安装则不渲染
const VxeUILoadingComponent = VxeUI.getComponent('VxeLoading');
const VxeUITooltipComponent = VxeUI.getComponent('VxeTooltip');
const $xeTabs = inject('$xeTabs', null);
const $xeParentTable = inject('$xeTable', null);
const $xeGrid = inject('$xeGrid', null);
const $xeGantt = inject('$xeGantt', null);
const $xeGGWrapper = $xeGrid || $xeGantt;
const { computeSize } = useFns.useSize(props);
const crossTableDragRowInfo = getCrossTableDragRowInfo();
const reactData = reactive(createReactData());
const internalData = createInternalData();
let tableMethods = {};
let tablePrivateMethods = {};
const refElem = ref();
const refVarElem = ref();
const refTooltip = ref();
const refCommTooltip = ref();
const refValidTooltip = ref();
const refTableMenu = ref();
const refTableFilter = ref();
const refTableCustom = ref();
const refTableViewportElem = ref();
const refTableHeader = ref();
const refTableBody = ref();
const refTableFooter = ref();
const refTableLeftHeader = ref();
const refTableLeftBody = ref();
const refTableLeftFooter = ref();
const refTableRightHeader = ref();
const refTableRightBody = ref();
const refTableRightFooter = ref();
const refTeleportWrapper = ref();
const refPopupWrapperElem = ref();
const refLeftContainer = ref();
const refRightContainer = ref();
const refColResizeBar = ref();
const refRowResizeBar = ref();
const refEmptyPlaceholder = ref();
const refDragTipElem = ref();
const refDragRowLineElem = ref();
const refDragColLineElem = ref();
const refRowExpandElem = ref();
const refRowExpandYSpaceElem = ref();
const refScrollXVirtualElem = ref();
const refScrollYVirtualElem = ref();
const refScrollXHandleElem = ref();
const refScrollXLeftCornerElem = ref();
const refScrollXRightCornerElem = ref();
const refScrollYHandleElem = ref();
const refScrollYTopCornerElem = ref();
const refScrollXWrapperElem = ref();
const refScrollYWrapperElem = ref();
const refScrollYBottomCornerElem = ref();
const refScrollXSpaceElem = ref();
const refScrollYSpaceElem = ref();
let $xeToolbar;
const computeTableId = computed(() => {
const { id } = props;
if (id) {
if (XEUtils.isFunction(id)) {
return `${id({ $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt }) || ''}`;
}
return `${id}`;
}
return '';
});
const computeRowField = computed(() => {
const rowOpts = computeRowOpts.value;
return `${props.rowId || rowOpts.keyField || '_X_ROW_KEY'}`;
});
const computeValidOpts = computed(() => {
const opts = Object.assign({}, getConfig().table.validConfig, props.validConfig);
// 兼容老版本
if (XEUtils.isBoolean(opts.showMessage)) {
opts.showErrorMessage = opts.showMessage;
}
return opts;
});
/**
* @deprecated
*/
const computeSXOpts = computed(() => {
const virtualXOpts = computeVirtualXOpts.value;
return virtualXOpts;
});
const computeScrollXThreshold = computed(() => {
const virtualXOpts = computeVirtualXOpts.value;
const { threshold } = virtualXOpts;
if (threshold) {
return XEUtils.toNumber(threshold);
}
return 0;
});
/**
* @deprecated
*/
const computeSYOpts = computed(() => {
const virtualYOpts = computeVirtualYOpts.value;
return virtualYOpts;
});
const computeVirtualXOpts = computed(() => {
const { virtualXConfig, scrollX } = props;
const globalVirtualXConfig = getConfig().table.virtualXConfig;
const globalScrollX = getConfig().table.scrollX;
if (virtualXConfig) {
return Object.assign({}, globalVirtualXConfig, virtualXConfig);
}
if (scrollX) {
// 已废弃,保留兼容
return Object.assign({}, globalScrollX, scrollX);
}
if (globalVirtualXConfig) {
return Object.assign({}, globalVirtualXConfig, virtualXConfig);
}
// 已废弃,保留兼容
return Object.assign({}, globalScrollX, scrollX);
});
const computeVirtualYOpts = computed(() => {
const { virtualYConfig, scrollY } = props;
const globalVirtualYConfig = getConfig().table.virtualYConfig;
const globalScrollY = getConfig().table.scrollY;
if (virtualYConfig) {
return Object.assign({}, globalVirtualYConfig, virtualYConfig);
}
if (scrollY) {
// 已废弃,保留兼容
return Object.assign({}, globalScrollY, scrollY);
}
if (globalVirtualYConfig) {
return Object.assign({}, globalVirtualYConfig, virtualYConfig);
}
// 已废弃,保留兼容
return Object.assign({}, globalScrollY, scrollY);
});
const computeScrollbarOpts = computed(() => {
return Object.assign({}, getConfig().table.scrollbarConfig, props.scrollbarConfig);
});
const computeScrollbarXOpts = computed(() => {
var _a;
const scrollbarOpts = computeScrollbarOpts.value;
return Object.assign({}, scrollbarOpts.x, ((_a = props.scrollbarConfig) === null || _a === void 0 ? void 0 : _a.x) || {});
});
const computeScrollbarYOpts = computed(() => {
var _a;
const scrollbarOpts = computeScrollbarOpts.value;
return Object.assign({}, scrollbarOpts.y, ((_a = props.scrollbarConfig) === null || _a === void 0 ? void 0 : _a.y) || {});
});
const computeScrollbarXToTop = computed(() => {
const scrollbarXOpts = computeScrollbarXOpts.value;
return scrollbarXOpts.position === 'top';
});
const computeScrollbarYToLeft = computed(() => {
const scrollbarYOpts = computeScrollbarYOpts.value;
return scrollbarYOpts.position === 'left';
});
const computeScrollYThreshold = computed(() => {
const virtualYOpts = computeVirtualYOpts.value;
const { threshold } = virtualYOpts;
if (threshold) {
return XEUtils.toNumber(threshold);
}
return 0;
});
const computeRowHeightMaps = computed(() => {
return reactData.rowHeightStore;
});
const computeDefaultRowHeight = computed(() => {
const vSize = computeSize.value;
const rowHeightMaps = computeRowHeightMaps.value;
return rowHeightMaps[vSize || 'default'] || 18;
});
const computeColumnOpts = computed(() => {
return Object.assign({}, getConfig().table.columnConfig, props.columnConfig);
});
const computeCurrentColumnOpts = computed(() => {
return Object.assign({}, getConfig().table.currentColumnConfig, props.currentColumnConfig);
});
const computeCellOpts = computed(() => {
const cellOpts = Object.assign({}, getConfig().table.cellConfig, props.cellConfig);
if (cellOpts.height) {
cellOpts.height = XEUtils.toNumber(cellOpts.height);
}
return cellOpts;
});
const computeHeaderCellOpts = computed(() => {
const headerCellOpts = Object.assign({}, getConfig().table.headerCellConfig, props.headerCellConfig);
const defaultRowHeight = computeDefaultRowHeight.value;
const cellOpts = computeCellOpts.value;
let headCellHeight = XEUtils.toNumber(getCalcHeight(headerCellOpts.height || cellOpts.height));
if ($xeGantt) {
const { computeTaskViewScales } = $xeGantt.getComputeMaps();
const taskViewScales = computeTaskViewScales.value;
if (taskViewScales && taskViewScales.length > 2) {
const ganttMinHeadCellHeight = defaultRowHeight / 2 * taskViewScales.length;
headCellHeight = Math.max(ganttMinHeadCellHeight, headCellHeight);
}
}
headerCellOpts.height = headCellHeight;
return headerCellOpts;
});
const computeFooterCellOpts = computed(() => {
const footerCellOpts = Object.assign({}, getConfig().table.footerCellConfig, props.footerCellConfig);
const cellOpts = computeCellOpts.value;
footerCellOpts.height = XEUtils.toNumber(getCalcHeight(footerCellOpts.height || cellOpts.height));
return footerCellOpts;
});
const computeRowOpts = computed(() => {
return Object.assign({}, getConfig().table.rowConfig, props.rowConfig);
});
const computeAggregateOpts = computed(() => {
return Object.assign({}, getConfig().table.aggregateConfig || getConfig().table.rowGroupConfig, props.aggregateConfig || props.rowGroupConfig);
});
const computeRowGroupOpts = computed(() => {
return computeAggregateOpts.value;
});
const computeAggregateAccuracyOpts = computed(() => {
return Object.assign({}, getConfig().table.aggregateAccuracyConfig, props.aggregateAccuracyConfig);
});
const computeCurrentRowOpts = computed(() => {
return Object.assign({}, getConfig().table.currentRowConfig, props.currentRowConfig);
});
const computeRowDragOpts = computed(() => {
return Object.assign({}, getConfig().table.rowDragConfig, props.rowDragConfig);
});
const computeColumnDragOpts = computed(() => {
return Object.assign({}, getConfig().table.columnDragConfig, props.columnDragConfig);
});
const computeResizeOpts = computed(() => {
return Object.assign({}, getConfig().table.resizeConfig, props.resizeConfig);
});
const computeResizableOpts = computed(() => {
return Object.assign({}, getConfig().table.resizableConfig, props.resizableConfig);
});
const computeSeqOpts = computed(() => {
return Object.assign({ startIndex: 0 }, getConfig().table.seqConfig, props.seqConfig);
});
const computeRadioOpts = computed(() => {
return Object.assign({}, getConfig().table.radioConfig, props.radioConfig);
});
const computeCheckboxOpts = computed(() => {
return Object.assign({}, getConfig().table.checkboxConfig, props.checkboxConfig);
});
const computeTooltipOpts = computed(() => {
return Object.assign({}, getConfig().tooltip, getConfig().table.tooltipConfig, props.tooltipConfig);
});
const computeHeaderTooltipOpts = computed(() => {
return Object.assign({}, getConfig().tooltip, getConfig().table.headerTooltipConfig, props.headerTooltipConfig);
});
const computeFooterTooltipOpts = computed(() => {
return Object.assign({}, getConfig().tooltip, getConfig().table.footerTooltipConfig, props.footerTooltipConfig);
});
const computeTableTipConfig = computed(() => {
const { tooltipStore } = reactData;
const tooltipOpts = computeTooltipOpts.value;
return Object.assign({}, tooltipOpts, tooltipStore.currOpts);
});
const computeValidTipConfig = computed(() => {
const tooltipOpts = computeTooltipOpts.value;
return Object.assign({}, tooltipOpts);
});
const computeEditOpts = computed(() => {
return Object.assign({}, getConfig().table.editConfig, props.editConfig);
});
const computeEditDirtyOpts = computed(() => {
return Object.assign({}, getConfig().table.editDirtyConfig, props.editDirtyConfig);
});
const computeSortOpts = computed(() => {
return Object.assign({ orders: ['asc', 'desc', null] }, getConfig().table.sortConfig, props.sortConfig);
});
const computeFilterOpts = computed(() => {
return Object.assign({}, getConfig().table.filterConfig, props.filterConfig);
});
const computeFloatingFilterOpts = computed(() => {
return Object.assign({}, getConfig().table.floatingFilterConfig, props.floatingFilterConfig);
});
const computeMouseOpts = computed(() => {
return Object.assign({}, getConfig().table.mouseConfig, props.mouseConfig);
});
const computeAreaOpts = computed(() => {
return Object.assign({}, getConfig().table.areaConfig, props.areaConfig);
});
const computeKeyboardOpts = computed(() => {
return Object.assign({}, getConfig().table.keyboardConfig, props.keyboardConfig);
});
const computeClipOpts = computed(() => {
return Object.assign({}, getConfig().table.clipConfig, props.clipConfig);
});
const computeUndoHistoryOpts = computed(() => {
return Object.assign({}, getConfig().table.undoHistoryConfig, props.undoHistoryConfig);
});
const computeFNROpts = computed(() => {
const fnrOpts = computeFnrOpts.value;
return fnrOpts;
});
const computeFnrOpts = computed(() => {
return Object.assign({}, getConfig().table.fnrConfig, props.fnrConfig);
});
const computeMenuOpts = computed(() => {
return Object.assign({}, getConfig().table.menuConfig, props.menuConfig);
});
const computeLeftFixedWidth = computed(() => {
const { columnStore } = reactData;
const { leftList } = columnStore;
let leftWidth = 0;
for (let i = 0; i < leftList.length; i++) {
const column = leftList[i];
leftWidth += column.renderWidth;
}
return leftWidth;
});
const computeRightFixedWidth = computed(() => {
const { columnStore } = reactData;
const { rightList } = columnStore;
let leftWidth = 0;
for (let i = 0; i < rightList.length; i++) {
const column = rightList[i];
leftWidth += column.renderWidth;
}
return leftWidth;
});
const computeBodyMergeCoverFixed = computed(() => {
const { columnStore, mergeBodyFlag } = reactData;
const { mergeBodyList, visibleColumn } = internalData;
const { leftList, rightList } = columnStore;
const rscIndex = visibleColumn.length - rightList.length;
if (mergeBodyFlag && (leftList.length || rightList.length)) {
const lecIndex = leftList.length;
for (let i = 0; i < mergeBodyList.length; i++) {
const { col, colspan } = mergeBodyList[i];
if (col < lecIndex || (col + colspan) > rscIndex) {
return true;
}
}
}
return false;
});
const computeIsHeaderRenderOptimize = computed(() => {
const { spanMethod, footerSpanMethod, showHeaderOverflow: allColumnHeaderOverflow } = props;
const { isGroup, scrollXLoad } = reactData;
let isOptimizeMode = false;
if (isGroup) {
// 分组表头
}
else {
// 如果是使用优化模式
if (scrollXLoad && allColumnHeaderOverflow) {
if (spanMethod || footerSpanMethod) {
// 如果不支持优化模式
}
else {
isOptimizeMode = true;
}
}
}
return isOptimizeMode;
});
const computeIsBodyRenderOptimize = computed(() => {
const { spanMethod, footerSpanMethod } = props;
const { scrollXLoad, scrollYLoad, isAllOverflow, expandColumn } = reactData;
const bodyMergeCoverFixed = computeBodyMergeCoverFixed.value;
const expandOpts = computeExpandOpts.value;
let isOptimizeMode = false;
// 如果是使用优化模式
if (scrollXLoad || scrollYLoad || isAllOverflow) {
// 如果是展开行,内联模式,不支持优化
// 如果是方法合并,不支持优化
// 如果固定列且配置式合并,不支持优化
if ((expandColumn && expandOpts.mode !== 'fixed') || bodyMergeCoverFixed || spanMethod || footerSpanMethod) {
// 如果不支持优化模式
}
else {
isOptimizeMode = true;
}
}
return isOptimizeMode;
});
const computeIsFooterRenderOptimize = computed(() => {
const { spanMethod, footerSpanMethod, showFooterOverflow: allColumnFooterOverflow } = props;
const { scrollXLoad } = reactData;
let isOptimizeMode = false;
// 如果是使用优化模式
if (scrollXLoad && allColumnFooterOverflow) {
if (spanMethod || footerSpanMethod) {
// 如果不支持优化模式
}
else {
isOptimizeMode = true;
}
}
return isOptimizeMode;
});
const computeHeaderMenu = computed(() => {
const menuOpts = computeMenuOpts.value;
const headerOpts = menuOpts.header;
return headerOpts && headerOpts.options ? headerOpts.options : [];
});
const computeBodyMenu = computed(() => {
const menuOpts = computeMenuOpts.value;
const bodyOpts = menuOpts.body;
return bodyOpts && bodyOpts.options ? bodyOpts.options : [];
});
const computeFooterMenu = computed(() => {
const menuOpts = computeMenuOpts.value;
const footerOpts = menuOpts.footer;
return footerOpts && footerOpts.options ? footerOpts.options : [];
});
const computeIsMenu = computed(() => {
const isContentMenu = computeIsContentMenu.value;
return isContentMenu;
});
const computeIsContentMenu = computed(() => {
const menuOpts = computeMenuOpts.value;
const headerMenu = computeHeaderMenu.value;
const bodyMenu = computeBodyMenu.value;
const footerMenu = computeFooterMenu.value;
return !!(props.menuConfig && isEnableConf(menuOpts) && (headerMenu.length || bodyMenu.length || footerMenu.length));
});
const computeMenuList = computed(() => {
const { ctxMenuStore } = reactData;
const rest = [];
ctxMenuStore.list.forEach((list) => {
list.forEach((item) => {
rest.push(item);
});
});
return rest;
});
const computeExportOpts = computed(() => {
return Object.assign({}, getConfig().table.exportConfig, props.exportConfig);
});
const computeImportOpts = computed(() => {
return Object.assign({}, getConfig().table.importConfig, props.importConfig);
});
const computePrintOpts = computed(() => {
return Object.assign({}, getConfig().table.printConfig, props.printConfig);
});
const computeExpandOpts = computed(() => {
return Object.assign({}, getConfig().table.expandConfig, props.expandConfig);
});
const computeTreeOpts = computed(() => {
return Object.assign({}, getConfig().table.treeConfig, props.treeConfig);
});
const computeEmptyOpts = computed(() => {
return Object.assign({}, getConfig().table.emptyRender, props.emptyRender);
});
const computeLoadingOpts = computed(() => {
return Object.assign({}, getConfig().table.loadingConfig, props.loadingConfig);
});
const computeCellOffsetWidth = computed(() => {
return props.border ? Math.max(2, Math.ceil(reactData.scrollbarWidth / reactData.tableColumn.length)) : 1;
});
const computeCustomOpts = computed(() => {
return Object.assign({}, getConfig().table.customConfig, props.customConfig);
});
const computeCustomSimpleMode = computed(() => {
const { minHeight, height } = props;
const customOpts = computeCustomOpts.value;
const { mode, popupOptions, placement } = customOpts;
if (!placement || placement === 'top-left' || placement === 'top-right') {
if (!(mode === 'modal' || mode === 'drawer')) {
const { mode } = popupOptions || {};
if (!mode || mode === 'auto') {
if (height || minHeight) {
return 'inside';
}
return 'outside';
}
if (mode) {
return mode;
}
}
}
return '';
});
const computeTableRowExpandedList = computed(() => {
const { tableData, rowExpandedFlag, expandColumn, rowGroupExpandedFlag, treeExpandedFlag } = reactData;
const { visibleDataRowIdData, rowExpandedMaps } = internalData;
const expandList = [];
if (tableData.length && expandColumn && rowExpandedFlag && rowGroupExpandedFlag && treeExpandedFlag) {
XEUtils.each(rowExpandedMaps, (row, rowid) => {
if (visibleDataRowIdData[rowid]) {
expandList.push(row);
}
});
}
return expandList;
});
const computeAutoWidthColumnList = computed(() => {
const { visibleColumn } = internalData;
const { tableColumn } = reactData;
return tableColumn.length || visibleColumn.length ? visibleColumn.filter(column => column.width === 'auto' || column.minWidth === 'auto') : [];
});
const computeFixedColumnSize = computed(() => {
const { tableColumn } = reactData;
const { collectColumn } = internalData;
let fixedSize = 0;
// 只判断第一层
if (tableColumn.length && collectColumn.length) {
collectColumn.forEach((column) => {
if (column.renderFixed) {
fixedSize++;
}
});
}
return fixedSize;
});
const computeIsMaxFixedColumn = computed(() => {
const fixedColumnSize = computeFixedColumnSize.value;
const columnOpts = computeColumnOpts.value;
const { maxFixedSize } = columnOpts;
if (maxFixedSize) {
return fixedColumnSize >= maxFixedSize;
}
return false;
});
const computeKeepFields = computed(() => {
const { tableFullColumn } = internalData;
const { updateColFlag } = reactData;
const editDirtyOpts = computeEditDirtyOpts.value;
const { includeFields, excludeFields } = editDirtyOpts;
const kpFields = [];
if (updateColFlag) {
if (includeFields && includeFields.length) {
return includeFields;
}
const exfMaps = {};
if (excludeFields && excludeFields.length) {
excludeFields.forEach(field => {
exfMaps[field] = 1;
});
}
for (let i = 0; i < tableFullColumn.length; i++) {
const column = tableFullColumn[i];
const { field, type, editRender, cellRender } = column;
if (field && !type && (editRender || cellRender) && !exfMaps[field]) {
kpFields.push(field);
}
}
}
return kpFields;
});
const computeTableBorder = computed(() => {
const { border } = props;
if (border === true) {
return 'full';
}
if (border) {
return border;
}
return 'default';
});
const computeIsAllCheckboxDisabled = computed(() => {
const { treeConfig } = props;
const { tableData } = reactData;
const { tableFullData } = internalData;
const checkboxOpts = computeCheckboxOpts.value;
const { strict, checkMethod } = checkboxOpts;
if (strict) {
if (tableData.length || tableFullData.length) {
if (checkMethod) {
if (treeConfig) {
// 暂时不支持树形结构
}
// 如果所有行都被禁用
return tableFullData.every((row) => !checkMethod({ $table: $xeTable, row }));
}
return false;
}
return true;
}
return false;
});
const computeVirtualScrollBars = computed(() => {
const { overflowX, scrollXLoad, overflowY, scrollYLoad } = reactData;
return {
x: overflowX && scrollXLoad,
y: overflowY && scrollYLoad
};
});
const computeRowGroupFields = computed(() => {
const rowGroupOpts = computeRowGroupOpts.value;
return rowGroupOpts.groupFields;
});
const computeRowGroupColumns = computed(() => {
const { rowGroupList } = reactData;
const { fullColumnFieldData } = internalData;
const rgColumns = [];
rowGroupList.forEach(aggConf => {
const colRest = fullColumnFieldData[aggConf.field];
if (colRest) {
rgColumns.push(colRest.column);
}
});
return rgColumns;
});
const computeAggFuncColumns = computed(() => {
const { rowGroupList, tableColumn } = reactData;
if (rowGroupList.length) {
return tableColumn.filter(column => column.aggFunc);
}
return [];
});
const refMaps = {
refElem,
refTooltip,
refValidTooltip,
refTableFilter,
refTableCustom,
refTableMenu,
refTableHeader,
refTableBody,
refTableFooter,
refTableLeftHeader,
refTableLeftBody,
refTableLeftFooter,
refTableRightHeader,
refTableRightBody,
refTableRightFooter,
refLeftContainer,
refRightContainer,
refColResizeBar,
refRowResizeBar,
refScrollXVirtualElem,
refScrollYVirtualElem,
refScrollXHandleElem,
refScrollYHandleElem,
refScrollXSpaceElem,
refScrollYSpaceElem
};
const computeMaps = {
computeSize,
computeTableId,
computeValidOpts,
computeRowField,
computeVirtualXOpts,
computeVirtualYOpts,
computeScrollbarOpts,
computeScrollbarXOpts,
computeScrollbarYOpts,
computeScrollbarXToTop,
computeScrollbarYToLeft,
computeColumnOpts,
computeCurrentColumnOpts,
computeScrollXThreshold,
computeScrollYThreshold,
computeRowHeightMaps,
computeDefaultRowHeight,
computeCellOpts,
computeHeaderCellOpts,
computeFooterCellOpts,
computeRowOpts,
computeAggregateOpts,
computeAggregateAccuracyOpts,
computeRowGroupOpts,
computeCurrentRowOpts,
computeRowDragOpts,
computeColumnDragOpts,
computeResizeOpts,
computeResizableOpts,
computeSeqOpts,
computeRadioOpts,
computeCheckboxOpts,
computeTooltipOpts,
computeHeaderTooltipOpts,
computeFooterTooltipOpts,
computeEditOpts,
computeEditDirtyOpts,
computeSortOpts,
computeFilterOpts,
computeFloatingFilterOpts,
computeMouseOpts,
computeAreaOpts,
computeKeyboardOpts,
computeClipOpts,
computeFnrOpts,
computeHeaderMenu,
computeBodyMenu,
computeFooterMenu,
computeIsMenu,
computeIsContentMenu,
computeMenuList,
computeMenuOpts,
computeExportOpts,
computeImportOpts,
computePrintOpts,
computeExpandOpts,
computeTreeOpts,
computeEmptyOpts,
computeLoadingOpts,
computeCellOffsetWidth,
computeCustomOpts,
computeCustomSimpleMode,
computeLeftFixedWidth,
computeRightFixedWidth,
computeBodyMergeCoverFixed,
computeFixedColumnSize,
computeIsMaxFixedColumn,
computeKeepFields,
computeIsAllCheckboxDisabled,
computeIsHeaderRenderOptimize,
computeIsBodyRenderOptimize,
computeIsFooterRenderOptimize,
computeVirtualScrollBars,
computeRowGroupFields,
computeRowGroupColumns,
computeAggFuncColumns,
computeUndoHistoryOpts,
computeFNROpts,
computeSXOpts,
computeSYOpts
};
const $xeTable = {
xID,
props: props,
context,
reactData,
internalData,
getRefMaps: () => refMaps,
getComputeMaps: () => computeMaps,
xeGrid: $xeGrid,
xeGantt: $xeGantt,
// 已废弃
xegrid: $xeGrid
};
const eqCellValue = (row1, row2, field) => {
const val1 = XEUtils.get(row1, field);
const val2 = XEUtils.get(row2, field);
if (eqEmptyValue(val1) && eqEmptyValue(val2)) {
return true;
}
if (XEUtils.isString(val1) || XEUtils.isNumber(val1)) {
return ('' + val1) === ('' + val2);
}
return XEUtils.isEqual(val1, val2);
};
const handleKeyField = () => {
const keyField = computeRowField.value;
internalData.currKeyField = keyField;
internalData.isCurrDeepKey = hasDeepKey(keyField);
};
const hangleStorageDefaultValue = (value, isAll) => {
return XEUtils.isBoolean(value) ? value : isAll;
};
const getNextSortOrder = (column) => {
const sortOpts = computeSortOpts.value;
const { orders = [] } = sortOpts;
const currOrder = column.order || null;
const oIndex = orders.indexOf(currOrder) + 1;
return orders[oIndex < orders.length ? oIndex : 0];
};
const getCustomStorageMap = (id) => {
const version = getConfig().version;
const rest = XEUtils.toStringJSON(localStorage.getItem(customStorageKey) || '');
const maps = rest && rest._v === version ? rest : { _v: version };
return (id ? maps[id] : maps) || {};
};
const setCustomStorageMap = (id, data) => {
const version = getConfig().version;
const maps = getCustomStorageMap();
maps[id] = data || undefined;
maps._v = version;
localStorage.setItem(customStorageKey, XEUtils.toJSONString(maps));
};
const getRecoverRowMaps = (keyMaps) => {
const { fullAllDataRowIdData } = internalData;
const restKeys = {};
XEUtils.each(keyMaps, (row, rowid) => {
if (fullAllDataRowIdData[rowid]) {
restKeys[rowid] = row;
}
});
return restKeys;
};
const handleReserveRow = (reserveRowMap) => {
const { fullDataRowIdData } = internalData;
const reserveList = [];
XEUtils.each(reserveRowMap, (item, rowid) => {
if (fullDataRowIdData[rowid] && $xeTable.findRowIndexOf(reserveList, fullDataRowIdData[rowid].row) === -1) {
reserveList.push(fullDataRowIdData[rowid].row);
}
});
return reserveList;
};
const handleVirtualXVisible = () => {
const { isScrollXBig, scrollXWidth } = reactData;
const { elemStore, visibleColumn, fullColumnIdData } = internalData;
const leftFixedWidth = computeLeftFixedWidth.value;
const rightFixedWidth = computeRightFixedWidth.value;
const bodyScrollElem = getRefElem(elemStore['main-body-scroll']);
if (bodyScrollElem) {
const clientWidth = bodyScrollElem.clientWidth;
let scrollLeft = bodyScrollElem.scrollLeft;
if (isScrollXBig) {
scrollLeft = Math.ceil((scrollXWidth - clientWidth) * Math.min(1, (scrollLeft / (maxXWidth - clientWidth))));
}
const startLeft = scrollLeft + leftFixedWidth;
const endLeft = scrollLeft + clientWidth - rightFixedWidth;
let leftIndex = 0;
let rightIndex = visibleColumn.length;
while (leftIndex < rightIndex) {
const cIndex = Math.floor((leftIndex + rightIndex) / 2);
const column = visibleColumn[cIndex];
const colid = column.id;
const colRest = fullColumnIdData[colid] || {};
if (colRest.oLeft <= startLeft) {
leftIndex = cIndex + 1;
}
else {
rightIndex = cIndex;
}
}
let visibleSize = 0;
const toVisibleIndex = leftIndex === visibleColumn.length ? leftIndex : Math.max(0, leftIndex < visibleColumn.length ? leftIndex - 2 : 0);
for (let cIndex = toVisibleIndex, cLen = visibleColumn.length; cIndex < cLen; cIndex++) {
const column = visibleColumn[cIndex];
const colid = column.id;
const colRest = fullColumnIdData[colid] || {};
visibleSize++;
if (colRest.oLeft > endLeft || visibleSize >= 60) {
break;
}
}
return { toVisibleIndex: Math.max(0, toVisibleIndex), visibleSize: Math.max(1, visibleSize) };
}
return { toVisibleIndex: 0, visibleSize: 6 };
};
const calcVarRowHeightConfig = (sizeKey, sizeEl) => {
const { rowHeightStore } = reactData;
if (sizeEl && sizeEl.clientHeight) {
rowHeightStore[sizeKey] = sizeEl.clientHeight;
}
};
const computeRowHeight = () => {
const { isAllOverflow } = reactData;
const tableHeader = refTableHeader.value;
const tableBody = refTableBody.value;
const tableBodyElem = tableBody ? tableBody.$el : null;
const defaultRowHeight = computeDefaultRowHeight.value;
let rowHeight = 0;
if (isAllOverflow) {
if (tableBodyElem) {
const tableHeaderElem = tableHeader ? tableHeader.$el : null;
let firstTrElem;
firstTrElem = tableBodyElem.querySelector('tr');
if (!firstTrElem && tableHeaderElem) {
firstTrElem = tableHeaderElem.querySelector('tr');
}
if (firstTrElem) {
rowHeight = firstTrElem.clientHeight;
}
}
if (!rowHeight) {
rowHeight = defaultRowHeight;
}
}
else {
rowHeight = defaultRowHeight;
}
// 最低支持 18px 行高
return Math.max(18, rowHeight);
};
const handleVirtualYVisible = () => {
const { isAllOverflow, expandColumn, isScrollYBig, scrollYHeight } = reactData;
const { elemStore, isResizeCellHeight, afterFullData, fullAllDataRowIdData } = internalData;
const rowOpts = computeRowOpts.value;
const cellOpts = computeCellOpts.value;
const defaultRowHeight = computeDefaultRowHeight.value;
const bodyScrollElem = getRefElem(elemStore['main-body-scroll']);
if (bodyScrollElem) {
const clientHeight = bodyScrollElem.clientHeight;
let scrollTop = bodyScrollElem.scrollTop;
if (isScrollYBig) {
scrollTop = Math.ceil((scrollYHeight - clientHeight) * Math.min(1, (scrollTop / (maxYHeight - clientHeight))));
}
const startTop = scrollTop;
const endTop = scrollTop + clientHeight;
let toVisibleIndex = -1;
let visibleSize = 0;
const isCustomCellHeight = isResizeCellHeight || cellOpts.height || rowOpts.height;
if (!isCustomCellHeight && !expandColumn && isAllOverflow) {
toVisibleIndex = Math.floor(startTop / defaultRowHeight) - 1;
visibleSize = Math.ceil(clientHeight / defaultRowHeight) + 1;
}
else {
const { handleGetRowId } = createHandleGetRowId($xeTable);
let leftIndex = 0;
let rightIndex = afterFullData.length;
while (leftIndex < rightIndex) {
const rIndex = Math.floor((leftIndex + rightIndex) / 2);
const row = afterFullData[rIndex];
const rowid = handleGetRowId(row);
const rowRest = fullAllDataRowIdData[rowid] || {};
if (rowRest.oTop <= startTop) {
leftIndex = rIndex + 1;
}
else {
rightIndex = rIndex;
}
}
toVisibleIndex = leftIndex === afterFullData.length ? leftIndex : Math.max(0, leftIndex < afterFullData.length ? leftIndex - 2 : 0);
for (let rIndex = toVisibleIndex, rLen = afterFullData.length; rIndex < rLen; rIndex++) {
const row = afterFullData[rIndex];
const rowid = handleGetRowId(row);
const rowRest = fullAllDataRowIdData[rowid] || {};
visibleSize++;
if (rowRest.oTop > endTop || visibleSize >= 100) {
break;
}
}
}
return { toVisibleIndex: Math.max(0, toVisibleIndex), visibleSize: Math.max(6, visibleSize) };
}
return { toVisibleIndex: 0, visibleSize: 6 };
};
const calculateMergerOffsetIndex = (list, offsetItem, type) => {
for (let mcIndex = 0, len = list.length; mcIndex < len; mcIndex++) {
const mergeItem = list[mcIndex];
const { startIndex, endIndex } = offsetItem;
const mergeStartIndex = mergeItem[type];
const mergeSpanNumber = mergeItem[type + 'span'];
const mergeEndIndex = mergeStartIndex + mergeSpanNumber;
if (mergeStartIndex < startIndex && startIndex < mergeEndIndex) {
offsetItem.startIndex = mergeStartIndex;
}
if (mergeStartIndex < endIndex && endIndex < mergeEndIndex) {
offsetItem.endIndex = mergeEndIndex;
}
if (offsetItem.startIndex !== startIndex || offsetItem.endIndex !== endIndex) {
mcIndex = -1;
}
}
};
function buildMergeData(mergeConfigs) {
const mergeMaps = {};
if (mergeConfigs && mergeConfigs.length) {
for (let mIndex = 0; mIndex < mergeConfigs.length; mIndex++) {
const { row: _rowIndex, col: _columnIndex, rowspan: mergeRowspan, colspan: mergeColspan } = mergeConfigs[mIndex];
for (let i = 0; i < mergeRowspan; i++) {
for (let j = 0; j < mergeColspan; j++) {
mergeMaps[`${_rowIndex + i}:${_columnIndex + j}`] = !i && !j
? {
rowspan: mergeRowspan,
colspan: mergeColspan
}
: {
rowspan: 0,
colspan: 0
};
}
}
}
}
return mergeMaps;
}
const handleUpdateMergeBodyCells = (merges) => {
internalData.mergeBodyList = [];
internalData.mergeBodyMaps = {};
internalData.mergeBodyCellMaps = {};
$xeTable.setMergeCells(merges);
};
const handleBodyMerge = (merges) => {
const { fullAllDataRowIdData, fullColumnIdData, visibleColumn, afterFullData, mergeBodyList, mergeBodyMaps } = internalData;
if (merges) {
const { handleGetRowId } = createHandleGetRowId($xeTable);
if (!XEUtils.isArray(merges)) {
merges = [merges];
}
merges.forEach((item) => {
let { row: margeRow, col: margeCol, rowspan, colspan } = item;
let mergeRowIndex = -1;
let mergeColumnIndex = -1;
if (XEUtils.isNumber(margeRow)) {
mergeRowIndex = margeRow;
}
else {
const rowid = margeRow ? handleGetRowId(margeRow) : null;
const rowRest = rowid ? fullAllDataRowIdData[rowid] : null;
if (rowRest) {
mergeRowIndex = rowRest._index;
}
}
if (XEUtils.isNumber(margeCol)) {
mergeColumnIndex = margeCol;
}
else {
const colid = margeCol ? margeCol.id : null;
const colRest = colid ? fullColumnIdData[colid] : null;
if (colRest) {
mergeColumnIndex = colRest._index;
}
}
if (mergeRowIndex > -1 && mergeColumnIndex > -1 && (rowspan || colspan)) {
rowspan = XEUtils.toNumber(rowspan) || 1;
colspan = XEUtils.toNumber(colspan) || 1;
if (rowspan > 1 || colspan > 1) {
const row = afterFullData[mergeRowIndex];
const column = visibleColumn[mergeColumnIndex];
let mergeItem = mergeBodyMaps[`${mergeRowIndex}:${mergeColumnIndex}`];
if (mergeItem) {
mergeItem.rowspan = rowspan;
mergeItem.colspan = colspan;
mergeItem._rowspan = rowspan;
mergeItem._colspan = colspan;
}
else {
mergeItem = {
row: mergeRowIndex,
col: mergeColumnIndex,
rowspan,
colspan,
_row: row,
_col: column,
_rowspan: rowspan,
_colspan: colspan
};
mergeBodyMaps[`${mergeRowIndex}:${mergeColumnIndex}`] = mergeItem;
mergeBodyList.push(mergeItem);
}
}
}
});
}
};
const removeBodyMerges = (merges) => {
const { mergeBodyList, fullColumnIdData, fullAllDataRowIdData, mergeBodyMaps } = internalData;
const rest = [];
if (merges) {
const { handleGetRowId } = createHandleGetRowId($xeTable);
if (!XEUtils.isArray(merges)) {
merges = [merges];
}
merges.forEach((item) => {
const { row: margeRow, col: margeCol } = item;
let mergeRowIndex = -1;
let mergeColumnIndex = -1;
if (XEUtils.isNumber(margeRow)) {
mergeRowIndex = margeRow;
}
else {
const rowid = margeRow ? handleGetRowId(margeRow) : null;
const rowRest = rowid ? fullAllDataRowIdData[rowid] : null;
if (rowRest) {
mergeRowIndex = rowRest._index;
}
}
if (XEUtils.isNumber(margeCol)) {
mergeColumnIndex = margeCol;
}
else {
const colid = margeCol ? margeCol.id : null;
const colRest = colid ? fullColumnIdData[colid] : null;
if (colRest) {
mergeColumnIndex = colRe