@blueking/vxe-table
Version:
一个基于 vue 的 PC 端表格组件,支持增删改查、虚拟树、列拖拽,懒加载、快捷菜单、数据校验、树形结构、打印、导入导出、自定义模板、渲染器、JSON 配置式...
566 lines (565 loc) • 22.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _vue = require("vue");
var _xeUtils = _interopRequireDefault(require("xe-utils"));
var _ui = require("../../ui");
var _util = require("./util");
var _dom = require("../../ui/src/dom");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const {
getI18n,
renderer,
renderEmptyElement
} = _ui.VxeUI;
const renderType = 'header';
var _default = exports.default = (0, _vue.defineComponent)({
name: 'VxeTableHeader',
props: {
tableData: Array,
tableColumn: Array,
tableGroupColumn: Array,
fixedColumn: Array,
fixedType: {
type: String,
default: null
}
},
setup(props) {
const $xeTable = (0, _vue.inject)('$xeTable', {});
const {
xID,
props: tableProps,
reactData: tableReactData,
internalData: tableInternalData
} = $xeTable;
const {
refElem: tableRefElem,
refLeftContainer,
refRightContainer,
refCellResizeBar,
refCellResizeTip
} = $xeTable.getRefMaps();
const {
computeColumnOpts,
computeColumnDragOpts,
computeResizableOpts
} = $xeTable.getComputeMaps();
const headerColumn = (0, _vue.ref)([]);
const refElem = (0, _vue.ref)();
const refHeaderScroll = (0, _vue.ref)();
const refHeaderTable = (0, _vue.ref)();
const refHeaderColgroup = (0, _vue.ref)();
const refHeaderTHead = (0, _vue.ref)();
const refHeaderXSpace = (0, _vue.ref)();
const refHeaderBorderRepair = (0, _vue.ref)();
const isShowSettingColumn = (0, _vue.computed)(() => Boolean($xeTable.context.slots.settingColumn) && props.fixedType !== 'left');
const uploadColumn = () => {
const {
isGroup
} = tableReactData;
headerColumn.value = isGroup ? (0, _util.convertHeaderColumnToRows)(props.tableGroupColumn) : [];
};
const resizeMousedownEvent = (evnt, params) => {
const {
column
} = params;
const {
fixedType
} = props;
const {
elemStore,
visibleColumn
} = tableInternalData;
const resizableOpts = computeResizableOpts.value;
const tableEl = tableRefElem.value;
const leftContainerElem = refLeftContainer.value;
const rightContainerElem = refRightContainer.value;
const resizeBarElem = refCellResizeBar.value;
const resizeTipElem = refCellResizeTip.value;
const {
clientX: dragClientX
} = evnt;
const wrapperElem = refElem.value;
const dragBtnElem = evnt.target;
let resizeColumn = column;
if (column.children && column.children.length) {
_xeUtils.default.eachTree(column.children, childColumn => {
resizeColumn = childColumn;
});
}
const cell = dragBtnElem.parentNode;
const cellParams = Object.assign(params, {
cell
});
let dragLeft = 0;
const bodyScrollElem = (0, _util.getRefElem)(elemStore['main-body-scroll']);
if (!bodyScrollElem) {
return;
}
const pos = (0, _dom.getOffsetPos)(dragBtnElem, wrapperElem);
const dragBtnWidth = dragBtnElem.clientWidth;
const dragBtnOffsetWidth = Math.floor(dragBtnWidth / 2);
const minInterval = (0, _util.getColReMinWidth)(cellParams) - dragBtnOffsetWidth; // 列之间的最小间距
let dragMinLeft = pos.left - cell.clientWidth + dragBtnWidth + minInterval;
let dragPosLeft = pos.left + dragBtnOffsetWidth;
const domMousemove = document.onmousemove;
const domMouseup = document.onmouseup;
const isLeftFixed = fixedType === 'left';
const isRightFixed = fixedType === 'right';
// 计算左右侧固定列偏移量
let fixedOffsetWidth = 0;
if (isLeftFixed || isRightFixed) {
const siblingProp = isLeftFixed ? 'nextElementSibling' : 'previousElementSibling';
let tempCellElem = cell[siblingProp];
while (tempCellElem) {
if ((0, _dom.hasClass)(tempCellElem, 'fixed--hidden')) {
break;
} else if (!(0, _dom.hasClass)(tempCellElem, 'col--group')) {
fixedOffsetWidth += tempCellElem.offsetWidth;
}
tempCellElem = tempCellElem[siblingProp];
}
if (isRightFixed && rightContainerElem) {
dragPosLeft = rightContainerElem.offsetLeft + fixedOffsetWidth;
}
}
// 处理拖动事件
const updateEvent = evnt => {
evnt.stopPropagation();
evnt.preventDefault();
const offsetX = evnt.clientX - dragClientX;
let left = dragPosLeft + offsetX;
const scrollLeft = fixedType ? 0 : bodyScrollElem.scrollLeft;
if (isLeftFixed) {
// 左固定列(不允许超过右侧固定列、不允许超过右边距)
left = Math.min(left, (rightContainerElem ? rightContainerElem.offsetLeft : bodyScrollElem.clientWidth) - fixedOffsetWidth - minInterval);
} else if (isRightFixed) {
// 右侧固定列(不允许超过左侧固定列、不允许超过左边距)
dragMinLeft = (leftContainerElem ? leftContainerElem.clientWidth : 0) + fixedOffsetWidth + minInterval;
left = Math.min(left, dragPosLeft + cell.clientWidth - minInterval);
} else {
dragMinLeft = Math.max(bodyScrollElem.scrollLeft, dragMinLeft);
// left = Math.min(left, bodyScrollElem.clientWidth + bodyScrollElem.scrollLeft - 40)
}
dragLeft = Math.max(left, dragMinLeft);
const resizeBarLeft = Math.max(1, dragLeft - scrollLeft);
resizeBarElem.style.left = `${resizeBarLeft}px`;
if (resizableOpts.showDragTip && resizeTipElem) {
const tableWidth = tableEl.clientWidth;
const wrapperRect = wrapperElem.getBoundingClientRect();
const resizeBarWidth = resizeBarElem.clientWidth;
const resizeTipWidth = resizeTipElem.clientWidth;
const resizeTipHeight = resizeTipElem.clientHeight;
let resizeTipLeft = -resizeTipWidth;
if (resizeBarLeft < resizeTipWidth + resizeBarWidth) {
resizeTipLeft = 0;
} else if (resizeBarLeft > tableWidth) {
resizeTipLeft += tableWidth - resizeBarLeft;
}
resizeTipElem.style.left = `${resizeTipLeft}px`;
resizeTipElem.style.top = `${Math.min(tableEl.clientHeight - resizeTipHeight, Math.max(0, evnt.clientY - wrapperRect.y - resizeTipHeight / 2))}px`;
resizeTipElem.textContent = getI18n('vxe.table.resizeColTip', [resizeColumn.renderWidth + (isRightFixed ? dragPosLeft - dragLeft : dragLeft - dragPosLeft)]);
}
};
tableReactData._isResize = true;
(0, _dom.addClass)(tableEl, 'drag--resize');
resizeBarElem.style.display = 'block';
document.onmousemove = updateEvent;
document.onmouseup = function (evnt) {
document.onmousemove = domMousemove;
document.onmouseup = domMouseup;
const resizeWidth = resizeColumn.renderWidth + (isRightFixed ? dragPosLeft - dragLeft : dragLeft - dragPosLeft);
resizeColumn.resizeWidth = resizeWidth;
if (resizableOpts.dragMode === 'fixed') {
visibleColumn.forEach(item => {
if (item.id !== resizeColumn.id) {
if (!item.resizeWidth) {
item.resizeWidth = item.renderWidth;
}
}
});
}
resizeBarElem.style.display = 'none';
tableReactData._isResize = false;
tableInternalData._lastResizeTime = Date.now();
$xeTable.analyColumnWidth();
$xeTable.recalculate(true).then(() => {
$xeTable.saveCustomStore('update:visible');
$xeTable.updateCellAreas();
$xeTable.dispatchEvent('resizable-change', Object.assign(Object.assign({}, params), {
resizeWidth
}), evnt);
setTimeout(() => $xeTable.recalculate(true), 300);
});
(0, _dom.removeClass)(tableEl, 'drag--resize');
};
updateEvent(evnt);
if ($xeTable.closeMenu) {
$xeTable.closeMenu();
}
};
const renderRows = (isGroup, isOptimizeMode, cols, $rowIndex) => {
const {
fixedType
} = props;
const {
resizable: allResizable,
border,
columnKey,
headerCellClassName,
headerCellStyle,
showHeaderOverflow: allColumnHeaderOverflow,
headerAlign: allHeaderAlign,
align: allAlign,
mouseConfig
} = tableProps;
const {
currentColumn,
scrollXLoad,
scrollYLoad,
overflowX
} = tableReactData;
const {
scrollXStore
} = tableInternalData;
const columnOpts = computeColumnOpts.value;
const columnDragOpts = computeColumnDragOpts.value;
const {
disabledMethod: dragDisabledMethod,
isCrossDrag,
isPeerDrag
} = columnDragOpts;
return cols.map((column, $columnIndex) => {
const {
type,
showHeaderOverflow,
headerAlign,
align,
filters,
headerClassName,
editRender,
cellRender
} = column;
const colid = column.id;
const renderOpts = editRender || cellRender;
const compConf = renderOpts ? renderer.get(renderOpts.name) : null;
const isColGroup = column.children && column.children.length;
const fixedHiddenColumn = fixedType ? column.fixed !== fixedType && !isColGroup : !!column.fixed && overflowX;
const headOverflow = _xeUtils.default.eqNull(showHeaderOverflow) ? allColumnHeaderOverflow : showHeaderOverflow;
const headAlign = headerAlign || (compConf ? compConf.tableHeaderCellAlign : '') || allHeaderAlign || align || (compConf ? compConf.tableCellAlign : '') || allAlign;
let showEllipsis = headOverflow === 'ellipsis';
const showTitle = headOverflow === 'title';
const showTooltip = headOverflow === true || headOverflow === 'tooltip';
let hasEllipsis = showTitle || showTooltip || showEllipsis;
let hasFilter = false;
let firstFilterOption = null;
if (filters) {
firstFilterOption = filters[0];
hasFilter = filters.some(item => item.checked);
}
const columnIndex = $xeTable.getColumnIndex(column);
const _columnIndex = $xeTable.getVTColumnIndex(column);
const params = {
$table: $xeTable,
$grid: $xeTable.xegrid,
$rowIndex,
column,
columnIndex,
$columnIndex,
_columnIndex,
firstFilterOption,
fixed: fixedType,
type: renderType,
isHidden: fixedHiddenColumn,
hasFilter
};
const thAttrs = {
colid,
colspan: column.colSpan > 1 ? column.colSpan : null,
rowspan: column.rowSpan > 1 ? column.rowSpan : null
};
const thOns = {
onClick: evnt => $xeTable.triggerHeaderCellClickEvent(evnt, params),
onDblclick: evnt => $xeTable.triggerHeaderCellDblclickEvent(evnt, params)
};
// 横向虚拟滚动不支持动态行高
if (scrollXLoad && !hasEllipsis) {
showEllipsis = hasEllipsis = true;
}
const isColDragCell = columnOpts.drag && columnDragOpts.trigger === 'cell';
let isDisabledDrag = false;
if (isColDragCell) {
isDisabledDrag = !!(dragDisabledMethod && dragDisabledMethod(params));
}
// 按下事件处理
if (mouseConfig || isColDragCell) {
thOns.onMousedown = evnt => $xeTable.triggerHeaderCellMousedownEvent(evnt, params);
}
// 拖拽列事件
if (columnOpts.drag) {
thOns.onDragstart = $xeTable.handleHeaderCellDragDragstartEvent;
thOns.onDragend = $xeTable.handleHeaderCellDragDragendEvent;
thOns.onDragover = $xeTable.handleHeaderCellDragDragoverEvent;
if (isColDragCell) {
thOns.onMouseup = $xeTable.handleHeaderCellDragMouseupEvent;
}
}
const isLastColumn = $columnIndex === cols.length - 1;
const showResizable = _xeUtils.default.isBoolean(column.resizable) ? column.resizable : columnOpts.resizable || allResizable;
const isAutoCellWidth = !column.resizeWidth && (column.minWidth === 'auto' || column.width === 'auto');
let isPreLoadStatus = false;
if (scrollXLoad && !isGroup && !column.fixed && (_columnIndex < scrollXStore.visibleStartIndex || _columnIndex > scrollXStore.visibleEndIndex)) {
isPreLoadStatus = true;
}
return (0, _vue.h)('th', Object.assign(Object.assign(Object.assign({
class: ['vxe-header--column', colid, {
[`col--${headAlign}`]: headAlign,
[`col--${type}`]: type,
'col--last': isLastColumn,
'col--fixed': column.fixed,
'col--group': isColGroup,
'col--ellipsis': hasEllipsis,
'fixed--width': !isAutoCellWidth,
'fixed--hidden': fixedHiddenColumn,
'is--sortable': column.sortable,
'col--filter': !!filters,
'is--filter-active': hasFilter,
'is--drag-active': !column.fixed && !isDisabledDrag && (isCrossDrag || isPeerDrag || !column.parentId),
'is--drag-disabled': isDisabledDrag,
'col--current': currentColumn === column
}, headerClassName ? _xeUtils.default.isFunction(headerClassName) ? headerClassName(params) : headerClassName : '', headerCellClassName ? _xeUtils.default.isFunction(headerCellClassName) ? headerCellClassName(params) : headerCellClassName : ''],
style: headerCellStyle ? _xeUtils.default.isFunction(headerCellStyle) ? headerCellStyle(params) : headerCellStyle : null
}, thAttrs), thOns), {
key: columnKey || scrollXLoad || scrollYLoad || columnOpts.useKey || columnOpts.drag || isColGroup ? colid : $columnIndex
}), [(0, _vue.h)('div', {
class: ['vxe-cell', {
'c--title': showTitle,
'c--tooltip': showTooltip,
'c--ellipsis': showEllipsis
}]
}, isPreLoadStatus || isOptimizeMode && fixedHiddenColumn ? [] : column.renderHeader(params)),
/**
* 列宽拖动
*/
!fixedHiddenColumn && showResizable ? (0, _vue.h)('div', {
class: ['vxe-resizable', {
'is--line': !border || border === 'none'
}],
onMousedown: evnt => resizeMousedownEvent(evnt, params),
onDblclick: evnt => $xeTable.handleResizeDblclickEvent(evnt, params)
}) : renderEmptyElement($xeTable)]);
}).concat(isShowSettingColumn.value && $rowIndex === 0 ? (0, _vue.h)('th', {
class: 'vxe-header--column vxe-header--setting-wrapper',
rowspan: headerColumn.value.length
}, renderSettingColumn()) : []);
};
const renderHeads = (isGroup, isOptimizeMode, headerGroups) => {
const {
fixedType
} = props;
const {
headerRowClassName,
headerRowStyle
} = tableProps;
const {
isDragColMove
} = tableReactData;
const columnOpts = computeColumnOpts.value;
const columnDragOpts = computeColumnDragOpts.value;
return headerGroups.map((cols, $rowIndex) => {
const params = {
$table: $xeTable,
$rowIndex,
fixed: fixedType,
type: renderType
};
if (columnOpts.drag && columnDragOpts.animation) {
return (0, _vue.h)(_vue.TransitionGroup, {
key: $rowIndex,
name: `vxe-header--col-list${isDragColMove ? '' : '-disabled'}`,
tag: 'tr',
class: ['vxe-header--row', headerRowClassName ? _xeUtils.default.isFunction(headerRowClassName) ? headerRowClassName(params) : headerRowClassName : ''],
style: headerRowStyle ? _xeUtils.default.isFunction(headerRowStyle) ? headerRowStyle(params) : headerRowStyle : null
}, {
default: () => renderRows(isGroup, isOptimizeMode, cols, $rowIndex)
});
}
return (0, _vue.h)('tr', {
key: $rowIndex,
class: ['vxe-header--row', headerRowClassName ? _xeUtils.default.isFunction(headerRowClassName) ? headerRowClassName(params) : headerRowClassName : ''],
style: headerRowStyle ? _xeUtils.default.isFunction(headerRowStyle) ? headerRowStyle(params) : headerRowStyle : null
}, renderRows(isGroup, isOptimizeMode, cols, $rowIndex));
});
};
const renderSettingColumn = () => {
if ($xeTable.context.slots.settingColumn) {
return $xeTable.callSlot($xeTable.context.slots.settingColumn, {});
}
return undefined;
};
const renderVN = () => {
const {
fixedType,
fixedColumn,
tableColumn
} = props;
const {
showHeaderOverflow: allColumnHeaderOverflow,
spanMethod,
footerSpanMethod
} = tableProps;
const {
isGroup,
scrollXLoad,
scrollYLoad,
dragCol
} = tableReactData;
const {
visibleColumn,
fullColumnIdData
} = tableInternalData;
let renderHeaderList = headerColumn.value;
let renderColumnList = tableColumn;
let isOptimizeMode = false;
if (isGroup) {
renderColumnList = visibleColumn;
} else {
// 如果是使用优化模式
if (scrollXLoad || scrollYLoad || allColumnHeaderOverflow) {
if (spanMethod || footerSpanMethod) {
// 如果不支持优化模式
} else {
isOptimizeMode = true;
}
}
if (fixedType) {
renderColumnList = visibleColumn;
// 如果是使用优化模式
if (isOptimizeMode) {
renderColumnList = fixedColumn || [];
}
}
renderHeaderList = [renderColumnList];
}
if (!fixedType && !isGroup) {
// 列拖拽
if (scrollXLoad && dragCol) {
if (renderColumnList.length > 2) {
const dCowRest = fullColumnIdData[dragCol.id];
if (dCowRest) {
const dcIndex = dCowRest._index;
const firstCol = renderColumnList[0];
const lastCol = renderColumnList[renderColumnList.length - 1];
const firstColRest = fullColumnIdData[firstCol.id];
const lastColRest = fullColumnIdData[lastCol.id];
if (firstColRest && lastColRest) {
const fcIndex = firstColRest._index;
const lcIndex = lastColRest._index;
if (dcIndex < fcIndex) {
renderColumnList = [dragCol].concat(renderColumnList);
renderHeaderList = [[dragCol].concat(renderHeaderList[0])].concat(renderHeaderList.slice(1));
} else if (dcIndex > lcIndex) {
renderColumnList = renderColumnList.concat([dragCol]);
renderHeaderList = [renderHeaderList[0].concat([dragCol])].concat(renderHeaderList.slice(1));
}
}
}
}
}
}
return (0, _vue.h)('div', {
ref: refElem,
class: ['vxe-table--header-wrapper', fixedType ? `fixed-${fixedType}--wrapper` : 'body--wrapper'],
xid: xID
}, [(0, _vue.h)('div', {
ref: refHeaderScroll,
class: 'vxe-table--header-inner-wrapper',
onScroll(evnt) {
$xeTable.triggerHeaderScrollEvent(evnt, fixedType);
}
}, [fixedType ? renderEmptyElement($xeTable) : (0, _vue.h)('div', {
ref: refHeaderXSpace,
class: 'vxe-body--x-space'
}), (0, _vue.h)('table', {
ref: refHeaderTable,
class: 'vxe-table--header',
xid: xID,
cellspacing: 0,
cellpadding: 0,
border: 0
}, [
/**
* 列宽
*/
(0, _vue.h)('colgroup', {
ref: refHeaderColgroup
}, renderColumnList.map((column, $columnIndex) => {
return (0, _vue.h)('col', {
name: column.id,
key: $columnIndex
});
}).concat(isShowSettingColumn.value ? (0, _vue.h)('col', {
name: 'col_setting'
}) : [])),
/**
* 头部
*/
(0, _vue.h)('thead', {
ref: refHeaderTHead
}, renderHeads(isGroup, isOptimizeMode, renderHeaderList))])]),
/**
* 其他
*/
(0, _vue.h)('div', {
ref: refHeaderBorderRepair,
class: 'vxe-table--header-border-line'
})]);
};
(0, _vue.watch)(() => props.tableColumn, uploadColumn);
(0, _vue.onMounted)(() => {
(0, _vue.nextTick)(() => {
const {
fixedType
} = props;
const {
internalData
} = $xeTable;
const {
elemStore
} = internalData;
const prefix = `${fixedType || 'main'}-header-`;
elemStore[`${prefix}wrapper`] = refElem;
elemStore[`${prefix}scroll`] = refHeaderScroll;
elemStore[`${prefix}table`] = refHeaderTable;
elemStore[`${prefix}colgroup`] = refHeaderColgroup;
elemStore[`${prefix}list`] = refHeaderTHead;
elemStore[`${prefix}xSpace`] = refHeaderXSpace;
elemStore[`${prefix}repair`] = refHeaderBorderRepair;
uploadColumn();
});
});
(0, _vue.onUnmounted)(() => {
const {
fixedType
} = props;
const {
internalData
} = $xeTable;
const {
elemStore
} = internalData;
const prefix = `${fixedType || 'main'}-header-`;
elemStore[`${prefix}wrapper`] = null;
elemStore[`${prefix}scroll`] = null;
elemStore[`${prefix}table`] = null;
elemStore[`${prefix}colgroup`] = null;
elemStore[`${prefix}list`] = null;
elemStore[`${prefix}xSpace`] = null;
elemStore[`${prefix}repair`] = null;
});
return renderVN;
}
});