UNPKG

@blueking/vxe-table

Version:

一个基于 vue 的 PC 端表格组件,支持增删改查、虚拟树、列拖拽,懒加载、快捷菜单、数据校验、树形结构、打印、导入导出、自定义模板、渲染器、JSON 配置式...

566 lines (565 loc) 22.1 kB
"use strict"; 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; } });