@blueking/vxe-table
Version:
一个基于 vue 的 PC 端表格组件,支持增删改查、虚拟树、列拖拽,懒加载、快捷菜单、数据校验、树形结构、打印、导入导出、自定义模板、渲染器、JSON 配置式...
1,566 lines (1,565 loc) • 380 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _vue = require("vue");
var _xeUtils = _interopRequireDefault(require("xe-utils"));
var _dom = require("../../ui/src/dom");
var _utils = require("../../ui/src/utils");
var _ui = require("../../ui");
var _cell = _interopRequireDefault(require("./cell"));
var _body = _interopRequireDefault(require("./body"));
var _header = _interopRequireDefault(require("./header"));
var _footer = _interopRequireDefault(require("./footer"));
var _props = _interopRequireDefault(require("./props"));
var _emits = _interopRequireDefault(require("./emits"));
var _util = require("./util");
var _vn = require("../../ui/src/vn");
var _log = require("../../ui/src/log");
var _panel = _interopRequireDefault(require("../module/custom/panel"));
var _panel2 = _interopRequireDefault(require("../module/filter/panel"));
var _importPanel = _interopRequireDefault(require("../module/export/import-panel"));
var _exportPanel = _interopRequireDefault(require("../module/export/export-panel"));
var _panel3 = _interopRequireDefault(require("../module/menu/panel"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const {
getConfig,
getIcon,
getI18n,
renderer,
formats,
createEvent,
globalResize,
interceptor,
hooks,
globalEvents,
GLOBAL_EVENT_KEYS,
useFns,
renderEmptyElement
} = _ui.VxeUI;
const customStorageKey = 'VXE_CUSTOM_STORE';
const settingColumnWidth = 40;
var _default = exports.default = (0, _vue.defineComponent)({
name: 'VxeTable',
props: _props.default,
emits: _emits.default,
setup(props, context) {
const {
slots,
emit
} = context;
const xID = _xeUtils.default.uniqueId();
// 使用已安装的组件,如果未安装则不渲染
const VxeUILoadingComponent = _ui.VxeUI.getComponent('VxeLoading');
const VxeUITooltipComponent = _ui.VxeUI.getComponent('VxeTooltip');
const $xeTabs = (0, _vue.inject)('$xeTabs', null);
const {
computeSize
} = useFns.useSize(props);
const reactData = (0, _vue.reactive)({
isCalcColumn: false,
// 低性能的静态列
staticColumns: [],
// 渲染的列分组
tableGroupColumn: [],
// 可视区渲染的列
tableColumn: [],
// 渲染中的数据
tableData: [],
// 是否启用了横向 X 可视渲染方式加载
scrollXLoad: false,
// 是否启用了纵向 Y 可视渲染方式加载
scrollYLoad: false,
// 是否存在纵向滚动条
overflowY: true,
// 是否存在横向滚动条
overflowX: false,
// 纵向滚动条的宽度
scrollbarWidth: 0,
// 横向滚动条的高度
scrollbarHeight: 0,
// 最后滚动时间戳
lastScrollTime: 0,
// 行高
rowHeight: 0,
// 表格父容器的高度
parentHeight: 0,
// 是否使用分组表头
isGroup: false,
isAllOverflow: false,
// 复选框属性,是否全选
isAllSelected: false,
// 复选框属性,有选中且非全选状态
isIndeterminate: false,
// 复选框属性,已选中的行集合
selectCheckboxMaps: {},
// 当前行
currentRow: null,
// 单选框属性,选中列
currentColumn: null,
// 单选框属性,选中行
selectRadioRow: null,
// 表尾合计数据
footerTableData: [],
// 展开列信息
expandColumn: null,
// 树节点列信息
treeNodeColumn: null,
hasFixedColumn: false,
// 已展开的行集合
rowExpandedMaps: {},
// 懒加载中的展开行的集合
rowExpandLazyLoadedMaps: {},
// 已展开树节点集合
treeExpandedMaps: {},
// 懒加载中的树节点的集合
treeExpandLazyLoadedMaps: {},
// 树节点不确定状态的集合
treeIndeterminateMaps: {},
// 合并单元格的对象集
mergeList: [],
// 合并表尾数据的对象集
mergeFooterList: [],
// 刷新列标识,当列筛选被改变时,触发表格刷新数据
upDataFlag: 0,
// 刷新列标识,当列的特定属性被改变时,触发表格刷新列
reColumnFlag: 0,
// 已标记的对象集
pendingRowMaps: {},
// 初始化标识
initStore: {
filter: false,
import: false,
export: false,
custom: false
},
// 自定义列相关的信息
customStore: {
btnEl: null,
isAll: false,
isIndeterminate: false,
activeBtn: false,
activeWrapper: false,
visible: false,
maxHeight: 0,
oldSortMaps: {},
oldFixedMaps: {},
oldVisibleMaps: {}
},
customColumnList: [],
// 当前选中的筛选列
filterStore: {
isAllSelected: false,
isIndeterminate: false,
style: null,
options: [],
column: null,
multiple: false,
visible: false,
maxHeight: null
},
// 存放列相关的信息
columnStore: {
leftList: [],
centerList: [],
rightList: [],
resizeList: [],
pxList: [],
pxMinList: [],
autoMinList: [],
scaleList: [],
scaleMinList: [],
autoList: [],
remainList: []
},
// 存放快捷菜单的信息
ctxMenuStore: {
selected: null,
visible: false,
showChild: false,
selectChild: null,
list: [],
style: null
},
// 存放可编辑相关信息
editStore: {
indexs: {
columns: []
},
titles: {
columns: []
},
// 选中源
selected: {
row: null,
column: null
},
// 已复制源
copyed: {
cut: false,
rows: [],
columns: []
},
// 激活
actived: {
row: null,
column: null
},
// 当前被强制聚焦单元格,只会在鼠标点击后算聚焦
focused: {
row: null,
column: null
},
insertMaps: {},
removeMaps: {}
},
// 存放 tooltip 相关信息
tooltipStore: {
row: null,
column: null,
content: null,
visible: false,
currOpts: {}
},
// 存放数据校验相关信息
validStore: {
visible: false
},
validErrorMaps: {},
// 导入相关信息
importStore: {
inited: false,
file: null,
type: '',
modeList: [],
typeList: [],
filename: '',
visible: false
},
importParams: {
mode: '',
types: null,
message: true
},
// 导出相关信息
exportStore: {
inited: false,
name: '',
modeList: [],
typeList: [],
columns: [],
isPrint: false,
hasFooter: false,
hasMerge: false,
hasTree: false,
hasColgroup: false,
visible: false
},
exportParams: {
filename: '',
sheetName: '',
mode: '',
type: '',
isColgroup: false,
isMerge: false,
isAllExpand: false,
useStyle: false,
original: false,
message: true,
isHeader: false,
isFooter: false
},
scrollVMLoading: false,
isCalcCellHeight: 0,
isCustomStatus: false,
isDragRowMove: false,
dragRow: null,
isDragColMove: false,
dragCol: null,
dragTipText: '',
_isResize: false,
isLoading: false
});
const internalData = {
tZindex: 0,
elemStore: {},
// 存放横向 X 虚拟滚动相关的信息
scrollXStore: {
preloadSize: 0,
offsetSize: 0,
visibleSize: 0,
visibleStartIndex: 0,
visibleEndIndex: 0,
startIndex: 0,
endIndex: 0
},
// 存放纵向 Y 虚拟滚动相关信息
scrollYStore: {
preloadSize: 0,
offsetSize: 0,
visibleSize: 0,
visibleStartIndex: 0,
visibleEndIndex: 0,
startIndex: 0,
endIndex: 0
},
// 表格宽度
tableWidth: 0,
// 表格高度
tableHeight: 0,
// 表头高度
headerHeight: 0,
// 表尾高度
footerHeight: 0,
customHeight: 0,
customMinHeight: 0,
customMaxHeight: 0,
// 当前 hover 行
hoverRow: null,
// 最后滚动位置
lastScrollLeft: 0,
lastScrollTop: 0,
// 单选框属性,已选中保留的行
radioReserveRow: null,
// 复选框属性,已选中保留的行集合
checkboxReserveRowMap: {},
// 行数据,已展开保留的行集合
rowExpandedReserveRowMap: {},
// 树结构数据,已展开保留的行集合
treeExpandedReserveRowMap: {},
// 树结构数据,不确定状态的集合
treeIndeterminateRowMaps: {},
// 列表完整数据、条件处理后
tableFullData: [],
afterFullData: [],
afterTreeFullData: [],
// 列表条件处理后数据集合
afterFullRowMaps: {},
// 树结构完整数据、条件处理后
tableFullTreeData: [],
tableSynchData: [],
tableSourceData: [],
// 收集的列配置(带分组)
collectColumn: [],
// 完整所有列(不带分组)
tableFullColumn: [],
// 渲染所有列
visibleColumn: [],
// 总的缓存数据集
fullAllDataRowIdData: {},
// 渲染中缓存数据
sourceDataRowIdData: {},
fullDataRowIdData: {},
fullColumnIdData: {},
fullColumnFieldData: {},
// 列选取状态
columnStatusMaps: {},
// 行选取状态
rowStatusMaps: {},
// prevDragRow: null,
inited: false,
tooltipTimeout: null,
initStatus: false,
isActivated: false
};
let tableMethods = {};
let tablePrivateMethods = {};
const refElem = (0, _vue.ref)();
const refTooltip = (0, _vue.ref)();
const refCommTooltip = (0, _vue.ref)();
const refValidTooltip = (0, _vue.ref)();
const refTableMenu = (0, _vue.ref)();
const refTableFilter = (0, _vue.ref)();
const refTableCustom = (0, _vue.ref)();
const refTableViewportElem = (0, _vue.ref)();
const refTableHeader = (0, _vue.ref)();
const refTableBodyPrepend = (0, _vue.ref)();
const refTableBody = (0, _vue.ref)();
const refTableFooter = (0, _vue.ref)();
const refTableBodyAppend = (0, _vue.ref)();
const refTableLeftHeader = (0, _vue.ref)();
const refTableLeftBody = (0, _vue.ref)();
const refTableLeftFooter = (0, _vue.ref)();
const refTableRightHeader = (0, _vue.ref)();
const refTableRightBody = (0, _vue.ref)();
const refTableRightFooter = (0, _vue.ref)();
const refLeftContainer = (0, _vue.ref)();
const refRightContainer = (0, _vue.ref)();
const refCellResizeBar = (0, _vue.ref)();
const refCellResizeTip = (0, _vue.ref)();
const refEmptyPlaceholder = (0, _vue.ref)();
const refDragTipElem = (0, _vue.ref)();
const refDragRowLineElem = (0, _vue.ref)();
const refDragColLineElem = (0, _vue.ref)();
const refScrollXVirtualElem = (0, _vue.ref)();
const refScrollYVirtualElem = (0, _vue.ref)();
const refScrollXHandleElem = (0, _vue.ref)();
const refScrollXRightCornerElem = (0, _vue.ref)();
const refScrollYHandleElem = (0, _vue.ref)();
const refScrollYTopCornerElem = (0, _vue.ref)();
const refScrollYBottomCornerElem = (0, _vue.ref)();
const refScrollXSpaceElem = (0, _vue.ref)();
const refScrollYSpaceElem = (0, _vue.ref)();
const $xeGrid = (0, _vue.inject)('$xeGrid', null);
let $xeToolbar;
const computeShowSettingColumn = (0, _vue.computed)(() => Boolean(slots.settingColumn));
const computeTableId = (0, _vue.computed)(() => {
const {
id
} = props;
if (id) {
if (_xeUtils.default.isFunction(id)) {
return `${id({
$table: $xeTable,
$grid: $xeGrid
}) || ''}`;
}
return `${id}`;
}
return '';
});
const computeValidOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.validConfig, props.validConfig);
});
/**
* @deprecated
*/
const computeSXOpts = (0, _vue.computed)(() => {
const virtualXOpts = computeVirtualXOpts.value;
return virtualXOpts;
});
const computeScrollXThreshold = (0, _vue.computed)(() => {
const sXOpts = computeSXOpts.value;
const {
threshold
} = sXOpts;
if (threshold) {
return _xeUtils.default.toNumber(threshold);
}
return 0;
});
/**
* @deprecated
*/
const computeSYOpts = (0, _vue.computed)(() => {
const virtualYOpts = computeVirtualYOpts.value;
return virtualYOpts;
});
const computeVirtualXOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.scrollX, getConfig().table.virtualXConfig, props.scrollX, props.virtualXConfig);
});
const computeVirtualYOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.scrollY, getConfig().table.virtualYConfig, props.scrollY, props.virtualYConfig);
});
const computeScrollbarOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.scrollbarConfig, props.scrollbarConfig);
});
const computeScrollYThreshold = (0, _vue.computed)(() => {
const sYOpts = computeSYOpts.value;
const {
threshold
} = sYOpts;
if (threshold) {
return _xeUtils.default.toNumber(threshold);
}
return 0;
});
const computeRowHeightMaps = (0, _vue.computed)(() => {
return {
default: 48,
medium: 44,
small: 40,
mini: 36
};
});
const computeDefaultRowHeight = (0, _vue.computed)(() => {
const vSize = computeSize.value;
const rowHeightMaps = computeRowHeightMaps.value;
return rowHeightMaps[vSize || 'default'];
});
const computeColumnOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.columnConfig, props.columnConfig);
});
const computeCellOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.cellConfig, props.cellConfig);
});
const computeRowOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.rowConfig, props.rowConfig);
});
const computeRowDragOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.rowDragConfig, props.rowDragConfig);
});
const computeColumnDragOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.columnDragConfig, props.columnDragConfig);
});
const computeResizeOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.resizeConfig, props.resizeConfig);
});
const computeResizableOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.resizableConfig, props.resizableConfig);
});
const computeSeqOpts = (0, _vue.computed)(() => {
return Object.assign({
startIndex: 0
}, getConfig().table.seqConfig, props.seqConfig);
});
const computeRadioOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.radioConfig, props.radioConfig);
});
const computeCheckboxOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.checkboxConfig, props.checkboxConfig);
});
const computeTooltipOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().tooltip, getConfig().table.tooltipConfig, props.tooltipConfig);
});
const computeEditOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.editConfig, props.editConfig);
});
const computeSortOpts = (0, _vue.computed)(() => {
return Object.assign({
orders: ['asc', 'desc', null]
}, getConfig().table.sortConfig, props.sortConfig);
});
const computeFilterOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.filterConfig, props.filterConfig);
});
const computeMouseOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.mouseConfig, props.mouseConfig);
});
const computeAreaOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.areaConfig, props.areaConfig);
});
const computeKeyboardOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.keyboardConfig, props.keyboardConfig);
});
const computeClipOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.clipConfig, props.clipConfig);
});
const computeFNROpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.fnrConfig, props.fnrConfig);
});
const computeMenuOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.menuConfig, props.menuConfig);
});
const computeLeftFixedWidth = (0, _vue.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 = (0, _vue.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 computeHeaderMenu = (0, _vue.computed)(() => {
const menuOpts = computeMenuOpts.value;
const headerOpts = menuOpts.header;
return headerOpts && headerOpts.options ? headerOpts.options : [];
});
const computeBodyMenu = (0, _vue.computed)(() => {
const menuOpts = computeMenuOpts.value;
const bodyOpts = menuOpts.body;
return bodyOpts && bodyOpts.options ? bodyOpts.options : [];
});
const computeFooterMenu = (0, _vue.computed)(() => {
const menuOpts = computeMenuOpts.value;
const footerOpts = menuOpts.footer;
return footerOpts && footerOpts.options ? footerOpts.options : [];
});
const computeIsMenu = (0, _vue.computed)(() => {
const menuOpts = computeMenuOpts.value;
const headerMenu = computeHeaderMenu.value;
const bodyMenu = computeBodyMenu.value;
const footerMenu = computeFooterMenu.value;
return !!(props.menuConfig && (0, _utils.isEnableConf)(menuOpts) && (headerMenu.length || bodyMenu.length || footerMenu.length));
});
const computeMenuList = (0, _vue.computed)(() => {
const {
ctxMenuStore
} = reactData;
const rest = [];
ctxMenuStore.list.forEach(list => {
list.forEach(item => {
rest.push(item);
});
});
return rest;
});
const computeExportOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.exportConfig, props.exportConfig);
});
const computeImportOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.importConfig, props.importConfig);
});
const computePrintOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.printConfig, props.printConfig);
});
const computeExpandOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.expandConfig, props.expandConfig);
});
const computeTreeOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.treeConfig, props.treeConfig);
});
const computeEmptyOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.emptyRender, props.emptyRender);
});
const computeLoadingOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.loadingConfig, props.loadingConfig);
});
const computeCellOffsetWidth = (0, _vue.computed)(() => {
return props.border ? Math.max(2, Math.ceil(reactData.scrollbarWidth / reactData.tableColumn.length)) : 1;
});
const computeCustomOpts = (0, _vue.computed)(() => {
return Object.assign({}, getConfig().table.customConfig, props.customConfig);
});
const computeAutoWidthColumnList = (0, _vue.computed)(() => {
const {
visibleColumn
} = internalData;
const {
tableColumn
} = reactData;
return tableColumn.length || visibleColumn.length ? visibleColumn.filter(column => column.width === 'auto' || column.minWidth === 'auto') : [];
});
const computeFixedColumnSize = (0, _vue.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 = (0, _vue.computed)(() => {
const fixedColumnSize = computeFixedColumnSize.value;
const columnOpts = computeColumnOpts.value;
const {
maxFixedSize
} = columnOpts;
if (maxFixedSize) {
return fixedColumnSize >= maxFixedSize;
}
return false;
});
const computeTableBorder = (0, _vue.computed)(() => {
const {
border
} = props;
if (border === true) {
return 'full';
}
if (border) {
return border;
}
return 'default';
});
const computeIsAllCheckboxDisabled = (0, _vue.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({
row
}));
}
return false;
}
return true;
}
return false;
});
const computeVirtualScrollBars = (0, _vue.computed)(() => {
const {
overflowX,
scrollXLoad,
overflowY,
scrollYLoad
} = reactData;
return {
x: overflowX && scrollXLoad,
y: overflowY && scrollYLoad
};
});
const refMaps = {
refElem,
refTooltip,
refValidTooltip,
refTableFilter,
refTableCustom,
refTableMenu,
refTableHeader,
refTableBody,
refTableFooter,
refTableLeftHeader,
refTableLeftBody,
refTableLeftFooter,
refTableRightHeader,
refTableRightBody,
refTableRightFooter,
refLeftContainer,
refRightContainer,
refCellResizeBar,
refCellResizeTip,
refScrollXVirtualElem,
refScrollYVirtualElem,
refScrollXHandleElem,
refScrollYHandleElem,
refScrollXSpaceElem,
refScrollYSpaceElem
};
const computeMaps = {
computeSize,
computeTableId,
computeValidOpts,
computeVirtualXOpts,
computeVirtualYOpts,
computeScrollbarOpts,
computeColumnOpts,
computeScrollXThreshold,
computeScrollYThreshold,
computeDefaultRowHeight,
computeCellOpts,
computeRowOpts,
computeRowDragOpts,
computeColumnDragOpts,
computeResizeOpts,
computeResizableOpts,
computeSeqOpts,
computeRadioOpts,
computeCheckboxOpts,
computeTooltipOpts,
computeEditOpts,
computeSortOpts,
computeFilterOpts,
computeMouseOpts,
computeAreaOpts,
computeKeyboardOpts,
computeClipOpts,
computeFNROpts,
computeHeaderMenu,
computeBodyMenu,
computeFooterMenu,
computeIsMenu,
computeMenuOpts,
computeExportOpts,
computeImportOpts,
computePrintOpts,
computeExpandOpts,
computeTreeOpts,
computeEmptyOpts,
computeLoadingOpts,
computeCellOffsetWidth,
computeCustomOpts,
computeLeftFixedWidth,
computeRightFixedWidth,
computeFixedColumnSize,
computeIsMaxFixedColumn,
computeIsAllCheckboxDisabled,
computeVirtualScrollBars,
computeSXOpts,
computeSYOpts
};
const $xeTable = {
xID,
props: props,
context,
reactData,
internalData,
getRefMaps: () => refMaps,
getComputeMaps: () => computeMaps,
xegrid: $xeGrid
};
const eqCellValue = (row1, row2, field) => {
const val1 = _xeUtils.default.get(row1, field);
const val2 = _xeUtils.default.get(row2, field);
if ((0, _utils.eqEmptyValue)(val1) && (0, _utils.eqEmptyValue)(val2)) {
return true;
}
if (_xeUtils.default.isString(val1) || _xeUtils.default.isNumber(val1)) {
return '' + val1 === '' + val2;
}
return _xeUtils.default.isEqual(val1, val2);
};
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.default.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.default.toJSONString(maps));
};
const getRecoverRowMaps = keyMaps => {
const {
fullAllDataRowIdData
} = internalData;
const restKeys = {};
_xeUtils.default.each(keyMaps, (row, rowid) => {
if (fullAllDataRowIdData[rowid]) {
restKeys[rowid] = row;
}
});
return restKeys;
};
const handleReserveRow = reserveRowMap => {
const {
fullDataRowIdData
} = internalData;
const reserveList = [];
_xeUtils.default.each(reserveRowMap, (item, rowid) => {
if (fullDataRowIdData[rowid] && $xeTable.findRowIndexOf(reserveList, fullDataRowIdData[rowid].row) === -1) {
reserveList.push(fullDataRowIdData[rowid].row);
}
});
return reserveList;
};
const handleVirtualXVisible = () => {
const {
elemStore,
visibleColumn
} = internalData;
const leftFixedWidth = computeLeftFixedWidth.value;
const rightFixedWidth = computeRightFixedWidth.value;
const bodyScrollElem = (0, _util.getRefElem)(elemStore['main-body-scroll']);
if (bodyScrollElem) {
const {
scrollLeft,
clientWidth
} = bodyScrollElem;
const startWidth = scrollLeft + leftFixedWidth;
const endWidth = scrollLeft + clientWidth - rightFixedWidth;
let toVisibleIndex = -1;
let cWidth = 0;
let visibleSize = 0;
for (let colIndex = 0, colLen = visibleColumn.length; colIndex < colLen; colIndex++) {
cWidth += visibleColumn[colIndex].renderWidth;
if (toVisibleIndex === -1 && startWidth < cWidth) {
toVisibleIndex = colIndex;
}
if (toVisibleIndex >= 0) {
visibleSize++;
if (cWidth > endWidth) {
break;
}
}
}
return {
toVisibleIndex: Math.max(0, toVisibleIndex),
visibleSize: Math.max(1, visibleSize)
};
}
return {
toVisibleIndex: 0,
visibleSize: 6
};
};
const computeRowHeight = () => {
const tableHeader = refTableHeader.value;
const tableBody = refTableBody.value;
const tableBodyElem = tableBody ? tableBody.$el : null;
const defaultRowHeight = computeDefaultRowHeight.value;
let rowHeight = 0;
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;
}
// 最低支持 18px 行高
return Math.max(18, rowHeight);
};
const handleVirtualYVisible = () => {
const {
showOverflow
} = props;
const {
rowHeight
} = reactData;
const {
elemStore,
afterFullData,
fullAllDataRowIdData
} = internalData;
const bodyScrollElem = (0, _util.getRefElem)(elemStore['main-body-scroll']);
if (bodyScrollElem) {
const {
scrollTop,
clientHeight
} = bodyScrollElem;
const endHeight = scrollTop + clientHeight;
let toVisibleIndex = -1;
let offsetTop = 0;
let visibleSize = 0;
if (showOverflow) {
toVisibleIndex = Math.floor(scrollTop / rowHeight);
visibleSize = Math.ceil(clientHeight / rowHeight) + 1;
} else {
for (let rIndex = 0, rLen = afterFullData.length; rIndex < rLen; rIndex++) {
const row = afterFullData[rIndex];
const rowid = (0, _util.getRowid)($xeTable, row);
const rowRest = fullAllDataRowIdData[rowid];
offsetTop += rowRest ? rowRest.height || rowHeight : rowHeight;
if (toVisibleIndex === -1 && scrollTop < offsetTop) {
toVisibleIndex = rIndex;
}
if (toVisibleIndex >= 0) {
visibleSize++;
if (offsetTop > endHeight) {
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;
}
}
};
const setMerges = (merges, mList, rowList) => {
if (merges) {
const {
treeConfig
} = props;
const {
visibleColumn
} = internalData;
if (!_xeUtils.default.isArray(merges)) {
merges = [merges];
}
if (treeConfig && merges.length) {
(0, _log.errLog)('vxe.error.noTree', ['merge-cells | merge-footer-items']);
}
merges.forEach(item => {
let {
row,
col,
rowspan,
colspan
} = item;
if (rowList && _xeUtils.default.isNumber(row)) {
row = rowList[row];
}
if (_xeUtils.default.isNumber(col)) {
col = visibleColumn[col];
}
if ((rowList ? row : _xeUtils.default.isNumber(row)) && col && (rowspan || colspan)) {
rowspan = _xeUtils.default.toNumber(rowspan) || 1;
colspan = _xeUtils.default.toNumber(colspan) || 1;
if (rowspan > 1 || colspan > 1) {
const mcIndex = _xeUtils.default.findIndexOf(mList, item => (item._row === row || (0, _util.getRowid)($xeTable, item._row) === (0, _util.getRowid)($xeTable, row)) && (item._col.id === col || item._col.id === col.id));
const mergeItem = mList[mcIndex];
if (mergeItem) {
mergeItem.rowspan = rowspan;
mergeItem.colspan = colspan;
mergeItem._rowspan = rowspan;
mergeItem._colspan = colspan;
} else {
const mergeRowIndex = rowList ? $xeTable.findRowIndexOf(rowList, row) : row;
const mergeColIndex = tableMethods.getVTColumnIndex(col);
mList.push({
row: mergeRowIndex,
col: mergeColIndex,
rowspan,
colspan,
_row: row,
_col: col,
_rowspan: rowspan,
_colspan: colspan
});
}
}
}
});
}
};
const removeMerges = (merges, mList, rowList) => {
const rest = [];
if (merges) {
const {
treeConfig
} = props;
const {
visibleColumn
} = internalData;
if (!_xeUtils.default.isArray(merges)) {
merges = [merges];
}
if (treeConfig && merges.length) {
(0, _log.errLog)('vxe.error.noTree', ['merge-cells | merge-footer-items']);
}
merges.forEach(item => {
let {
row,
col
} = item;
if (rowList && _xeUtils.default.isNumber(row)) {
row = rowList[row];
}
if (_xeUtils.default.isNumber(col)) {
col = visibleColumn[col];
}
const mcIndex = _xeUtils.default.findIndexOf(mList, item => (item._row === row || (0, _util.getRowid)($xeTable, item._row) === (0, _util.getRowid)($xeTable, row)) && (item._col.id === col || item._col.id === col.id));
if (mcIndex > -1) {
const rItems = mList.splice(mcIndex, 1);
rest.push(rItems[0]);
}
});
}
return rest;
};
const clearAllSort = () => {
const {
tableFullColumn
} = internalData;
tableFullColumn.forEach(column => {
column.order = null;
});
};
const calcTableHeight = key => {
const {
parentHeight
} = reactData;
const val = props[key];
let num = 0;
if (val) {
if (val === '100%' || val === 'auto') {
num = parentHeight;
} else {
const excludeHeight = $xeTable.getExcludeHeight();
if ((0, _dom.isScale)(val)) {
num = Math.floor((_xeUtils.default.toInteger(val) || 1) / 100 * parentHeight);
} else {
num = _xeUtils.default.toNumber(val);
}
num = Math.max(40, num - excludeHeight);
}
}
return num;
};
const handleCustomRestore = storeData => {
let {
collectColumn
} = internalData;
const {
resizableData,
sortData,
visibleData,
fixedData
} = storeData;
let hasCustomSort = false;
// 处理还原
if (resizableData || sortData || visibleData || fixedData) {
_xeUtils.default.eachTree(collectColumn, (column, index, items, path, parentColumn) => {
const colKey = column.getKey();
// 支持一级
if (!parentColumn) {
if (fixedData && fixedData[colKey] !== undefined) {
column.fixed = fixedData[colKey];
}
if (sortData && _xeUtils.default.isNumber(sortData[colKey])) {
hasCustomSort = true;
column.renderSortNumber = sortData[colKey];
}
}
if (resizableData && _xeUtils.default.isNumber(resizableData[colKey])) {
column.resizeWidth = resizableData[colKey];
}
if (visibleData && _xeUtils.default.isBoolean(visibleData[colKey])) {
column.visible = visibleData[colKey];
}
});
// 如果自定义了顺序
if (hasCustomSort) {
collectColumn = _xeUtils.default.orderBy(collectColumn, 'renderSortNumber');
internalData.collectColumn = collectColumn;
internalData.tableFullColumn = getColumnList(collectColumn);
}
reactData.isCustomStatus = true;
} else {
reactData.isCustomStatus = false;
}
};
/**
* 还原自定义列操作状态
*/
const restoreCustomStorage = () => {
const {
customConfig
} = props;
const tableId = computeTableId.value;
const customOpts = computeCustomOpts.value;
const {
storage,
restoreStore
} = customOpts;
const isAllCustom = storage === true;
const storageOpts = isAllCustom ? {} : Object.assign({}, storage || {});
const isCustomResizable = isAllCustom || storageOpts.resizable;
const isCustomVisible = isAllCustom || storageOpts.visible;
const isCustomFixed = isAllCustom || storageOpts.fixed;
const isCustomSort = isAllCustom || storageOpts.sort;
if ((customConfig ? (0, _utils.isEnableConf)(customOpts) : customOpts.enabled) && (isCustomResizable || isCustomVisible || isCustomFixed || isCustomSort)) {
if (!tableId) {
(0, _log.errLog)('vxe.error.reqProp', ['id']);
return;
}
const storeData = getCustomStorageMap(tableId);
if (restoreStore) {
return Promise.resolve(restoreStore({
id: tableId,
type: 'restore',
storeData
})).then(storeData => {
if (!storeData) {
return;
}
return handleCustomRestore(storeData);
}).catch(e => e);
} else {
return handleCustomRestore(storeData);
}
}
};
/**
* 更新数据列的 Map
* 牺牲数据组装的耗时,用来换取使用过程中的流畅
*/
const cacheColumnMap = () => {
const {
tableFullColumn,
collectColumn
} = internalData;
const fullColumnIdData = internalData.fullColumnIdData = {};
const fullColumnFieldData = internalData.fullColumnFieldData = {};
const mouseOpts = computeMouseOpts.value;
const columnOpts = computeColumnOpts.value;
const columnDragOpts = computeColumnDragOpts.value;
const {
isCrossDrag,
isSelfToChildDrag
} = columnDragOpts;
const customOpts = computeCustomOpts.value;
const {
storage
} = customOpts;
const rowOpts = computeRowOpts.value;
const isGroup = collectColumn.some(_utils.hasChildrenList);
let isAllOverflow = !!props.showOverflow;
let expandColumn;
let treeNodeColumn;
let checkboxColumn;
let radioColumn;
let htmlColumn;
let hasFixed;
const handleFunc = (column, index, items, path, parentColumn) => {
const {
id: colid,
field,
fixed,
type,
treeNode
} = column;
const rest = {
$index: -1,
_index: -1,
column,
colid,
index,
items,
parent: parentColumn || null,
width: 0
};
if (field) {
if (fullColumnFieldData[field]) {
(0, _log.errLog)('vxe.error.colRepet', ['field', field]);
}
fullColumnFieldData[field] = rest;
} else {
if (storage && !type || columnOpts.drag && (isCrossDrag || isSelfToChildDrag)) {
(0, _log.errLog)('vxe.error.reqProp', [`${column.getTitle() || type || ''} -> column.field`]);
}
}
if (!hasFixed && fixed) {
hasFixed = fixed;
}
if (!htmlColumn && type === 'html') {
htmlColumn = column;
}
if (treeNode) {
if (process.env.NODE_ENV === 'development') {
if (treeNodeColumn) {
(0, _log.warnLog)('vxe.error.colRepet', ['tree-node', treeNode]);
}
}
if (!treeNodeColumn) {
treeNodeColumn = column;
}
} else if (type === 'expand') {
if (process.env.NODE_ENV === 'development') {
if (expandColumn) {
(0, _log.warnLog)('vxe.error.colRepet', ['type', type]);
}
}
if (!expandColumn) {
expandColumn = column;
}
}
if (process.env.NODE_ENV === 'development') {
if (type === 'checkbox') {
if (checkboxColumn) {
(0, _log.warnLog)('vxe.error.colRepet', ['type', type]);
}
if (!checkboxColumn) {
checkboxColumn = column;
}
} else if (type === 'radio') {
if (radioColumn) {
(0, _log.warnLog)('vxe.error.colRepet', ['type', type]);
}
if (!radioColumn) {
radioColumn = column;
}
}
}
if (isAllOverflow && column.showOverflow === false) {
isAllOverflow = false;
}
if (fullColumnIdData[colid]) {
(0, _log.errLog)('vxe.error.colRepet', ['colId', colid]);
}
fullColumnIdData[colid] = rest;
};
if (isGroup) {
_xeUtils.default.eachTree(collectColumn, (column, index, items, path, parentColumn, nodes) => {
column.level = nodes.length;
handleFunc(column, index, items, path, parentColumn);
});
} else {
tableFullColumn.forEach(handleFunc);
}
if (process.env.NODE_ENV === 'development') {
if (expandColumn && mouseOpts.area) {
(0, _log.errLog)('vxe.error.errConflicts', ['mouse-config.area', 'column.type=expand']);
}
}
if (process.env.NODE_ENV === 'development') {
if (htmlColumn) {
if (!columnOpts.useKey) {
(0, _log.errLog)('vxe.error.reqProp', ['column-config.useKey & column.type=html']);
}
if (!rowOpts.useKey) {
(0, _log.errLog)('vxe.error.reqProp', ['row-config.useKey & column.type=html']);
}
}
}
reactData.isGroup = isGroup;
reactData.treeNodeColumn = treeNodeColumn;
reactData.expandColumn = expandColumn;
reactData.isAllOverflow = isAllOverflow;
};
const updateHeight = () => {
internalData.customHeight = calcTableHeight('height');
internalData.customMinHeight = calcTableHeight('minHeight');
internalData.customMaxHeight = calcTableHeight('maxHeight');
};
const calcColumnAutoWidth = (column, wrapperEl) => {
const cellElList = wrapperEl.querySelectorAll(`.vxe-header--column.${column.id}>.vxe-cell,.vxe-body--column.${column.id}>.vxe-cell,.vxe-footer--column.${column.id}>.vxe-cell`);
const firstCellEl = cellElList[0];
let paddingSize = 0;
if (firstCellEl) {
const cellStyle = getComputedStyle(firstCellEl);
paddingSize = Math.floor(_xeUtils.default.toNumber(cellStyle.paddingLeft) + _xeUtils.default.toNumber(cellStyle.paddingRight)) + 2;
}
let colWidth = column.renderAutoWidth - paddingSize;
_xeUtils.default.arrayEach(cellElList, itemEl => {
const cellEl = itemEl;
const thElem = cellEl.parentElement;
let titleWidth = 0;
if (`${thElem.tagName}`.toLowerCase() === 'th') {
_xeUtils.default.arrayEach(cellEl.children, btnEl => {
titleWidth += btnEl.offsetWidth + 1;
});
} else {
const labelEl = cellEl.firstElementChild;
if (labelEl) {
titleWidth = labelEl.offsetWidth;
}
}
if (titleWidth) {
colWidth = Math.max(colWidth, Math.ceil(titleWidth) + 4);
}
});
return colWidth + paddingSize;
};
const calcCellWidth = () => {
const autoWidthColumnList = computeAutoWidthColumnList.value;
reactData.isCalcColumn = true;
return (0, _vue.nextTick)().then(() => {
const {
fullColumnIdData
} = internalData;
const el = refElem.value;
if (el) {
autoWidthColumnList.forEach(column => {
const colid = column.id;
const colRest = fullColumnIdData[colid];
const colWidth = calcColumnAutoWidth(column, el);
if (colRest) {
colRest.width = Math.max(colWidth, colRest.width);
}
column.renderAutoWidth = colWidth;
});
$xeTable.analyColumnWidth();
}
reactData.isCalcColumn = false;
});
};
/**
* 列宽算法,计算单元格列宽,动态分配可用剩余空间
* 支持 px、%、固定 混合分配
* 支持动态列表调整分配
* 支持自动分配偏移量
* 支持 width=60 width=60px width=10% min-width=60 min-width=60px min-width=10%
*/
const autoCellWidth = () => {
const {
elemStore
} = internalData;
const scrollbarOpts = computeScrollbarOpts.value;
const tableBody = refTableBody.value;
const tableAppendElem = refTableBodyAppend.value;
const bodyElem = tableBody ? tableBody.$el : null;
if (!bodyElem) {
return;
}
const yHandleEl = refScrollYHandleElem.value;
if (!yHandleEl) {
return;
}
const xHandleEl = refScrollXHandleElem.value;
if (!xHandleEl) {
return;
}
let tableWidth = 0;
const minCellWidth = 40; // 列宽最少限制 40px
const bodyWidth = bodyElem.clientWidth;
let remainWidth = bodyWidth;
let meanWidth = remainWidth / 100;
const {
fit
} = props;
const {
columnStore
} = reactData;
const {
resizeList,
pxMinList,
autoMinList,
pxList,
scaleList,
scaleMinList,
autoList,
remainList
} = columnStore;
// 最小宽
pxMinList.forEach(column => {
const minWidth = _xeUtils.default.toInteger(column.minWidth);
tableWidth += minWidth;
column.renderWidth = minWidth;
});
// 最小自适应
autoMinList.forEach(column => {
const scaleWidth = Math.max(60, _xeUtils.default.toInteger(column.renderAutoWidth));
tableWidth += scaleWidth;
column.renderWidth = scaleWidth;
});
// 最小百分比
scaleMinList.forEach(column => {
const scaleWidth = Math.floor(_xeUtils.default.toInteger(column.minWidth) * meanWidth);
tableWidth += scaleWidth;
column.renderWidth = scaleWidth;
});
// 固定百分比
scaleList.forEach(column => {
const scaleWidth = Math.floor(_xeUtils.default.toInteger(column.width) * meanWidth);
tableWidth += scaleWidth;
column.renderWidth = scaleWidth;
});
// 固定宽
pxList.forEach(column => {
const width = _xeUtils.default.toInteger(column.width);
tableWidth += width;
column.renderWidth = width;
});
// 自适应宽
autoList.forEach(column => {
const width = Math.max(60, _xeUtils.default.toInteger(column.renderAutoWidth));
tableWidth += width;
column.renderWidth = width;
});
// 调整了列宽
resizeList.forEach(column => {
const width = _xeUtils.default.toInteger(column.resizeWidth);
tableWidth += width;
column.renderWidth = width;
});
// 有右上角设置列需要加上宽度
if (computeShowSettingColumn.value) {
tableWidth += settingColumnWidth;
}
remainWidth -= tableWidth;
meanWidth = remainWidth > 0 ? Math.floor(remainWidth / (scaleMinList.length + pxMinList.length + autoMinList.length + remainList.length)) : 0;
if (fit) {
if (remainWidth > 0) {
scaleMinList.concat(pxMinList).concat(autoMinList).forEach(column => {
tableWidth += meanWidth;
column.renderWidth += meanWidth;
});
}
} else {
meanWidth = minCellWidth;
}
// 剩余均分
remainList.forEach(column => {
const width = Math.max(meanWidth, minCellWidth);
column.renderWidth = width;
tableWidth += width;
});
if (fit) {
/**
* 偏移量算法
* 如果所有列足够放的情况下,从最后动态列开始分配
*/
const dynamicList = scaleList.concat(scaleMinList).concat(pxMinList).concat(autoMinList).concat(remainList);
let dynamicSize = dynamicList.length - 1;
if (dynamicSize > 0) {
let i = bodyWidth - tableWidth;
if (i > 0) {
while (i > 0 && dynamicSize >= 0) {
i--;
dynamicList[dynamicSize--].renderWidth++;
}
tableWidth = bodyWidth;
}
}
}
const tableHeight = bodyElem.offsetHeight;
const overflowY = yHandleEl.scrollHeight > yHandleEl.clientHeight;
reactData.scrollbarWidth = overflowY ? Math.max(scrollbarOpts.width || 0, yHandleEl.offsetWidth - yHandleEl.clientWidth) : 0;
reactData.overflowY = overflowY;
internalData.tableWidth = tableWidth;
internalData.tableHeight = tableHeight;
const headerTableElem = (0, _util.getRefElem)(elemStore['main-header-table']);
const footerTableElem = (0, _util.getRefElem)(elemStore['main-footer-table']);
const headerHeight = headerTableElem ? headerTableElem.clientHeight : 0;
const overflowX = tableWidth > bodyWidth;
let footerHeight = footerTableElem ? footerTableElem.clientHeight : 0;
if (tableAppendElem) {
footerHeight += tableAppendElem.offsetHeight;
}
reactData.scrollbarHeight = overflowX ? Math.max(scrollbarOpts.height || 0, xHandleEl.offsetHeight - xHandleEl.clientHeight) : 0;
internalData.headerHeight = headerHeight;
internalData.footerHeight = footerHeight;
reactData.overflowX = overflowX;
updateHeight();
reactData.parentHeight = Math.max(internalData.headerHeight + footerHeight + 20, $xeTable.getParentHeight());
if (overflowX) {
$xeTable.checkScrolling();
}
};
// const updateCellOffset = () => {
// const { chTimeout, chRunTime } = inte