UNPKG

vue-fantable

Version:
1,621 lines (1,441 loc) 45.4 kB
import { clsName, isLastColumnByColKey, isLastRowByRowKey, getColKeysByRangeColKeys, isExistGivenFixedColKey, isExistNotFixedColKey, getLeftmostColKey, getRightmostColKey, getColKeysByFixedTypeWithinColKeys, getTotalWidthByColKeys, getPreviewColKey, getNextColKey, } from '../util/index' import { HOOKS_NAME, AUTOFILLING_DIRECTION, CURRENT_CELL_SELECTION_TYPES, COLUMN_FIXED_TYPE, } from '../util/constant' import { INSTANCE_METHODS } from './constant' import { isEmptyValue, isBoolean } from '../../../src/utils/index.js' import { debounce } from '@P/src/utils/index.js' // import eventCenter from '@P/events/event-center' import { GLOBAL_EVENT } from '@P/events/global-events' export default { // name: COMPS_NAME.FAN_TABLE_SELECTION, name: 'FanTableSelection', inject: ['eventCenter'], props: { tableEl: { type: HTMLTableElement, default: null, }, allRowKeys: { type: Array, required: true, }, colgroups: { type: Array, required: true, }, parentRendered: { type: Boolean, required: true, }, hooks: { type: Object, required: true, }, // cell autofill option cellAutofillOption: { type: [Object, Boolean], default: function () { return null }, }, cellSelectionData: { type: Object, required: true, }, cellSelectionRangeData: { type: Object, required: true, }, isAutofillStarting: { type: Boolean, required: true, }, currentCellSelectionType: { type: String, default: '', }, // is scrolling showVirtualScrollingPlaceholder: { type: Boolean, default: false, }, isVirtualScroll: { type: Boolean, default: false, }, virtualScrollVisibleIndexs: { type: Object, required: true, }, isCellEditing: { type: Boolean, default: false, }, }, emits: ['cellSelectionRangeDataChange'], data() { return { // current cell currentCellEl: null, normalEndCellEl: null, autoFillEndCellEl: null, // cell selection rect cellSelectionRect: { // current cell element rect currentCellRect: { left: 0, top: 0, width: 0, height: 0, }, // normal end cell element rect normalEndCellRect: { left: 0, top: 0, width: 0, height: 0, }, // auto fill end cell element rect autoFillEndCellRect: { left: 0, top: 0, width: 0, height: 0, }, }, } }, computed: { // selection borders visibility selectionBordersVisibility() { let result = true if (this.isVirtualScroll) { const { showVirtualScrollingPlaceholder, cellSelectionData, virtualScrollVisibleIndexs, currentCellSelectionType, } = this if (showVirtualScrollingPlaceholder) { result = false } else { const { currentCell, normalEndCell } = cellSelectionData if ( currentCellSelectionType === CURRENT_CELL_SELECTION_TYPES.SINGLE ) { if ( currentCell.rowIndex < virtualScrollVisibleIndexs.start || currentCell.rowIndex > virtualScrollVisibleIndexs.end ) { result = false } } if ( currentCellSelectionType === CURRENT_CELL_SELECTION_TYPES.RANGE ) { if ( (currentCell.rowIndex < virtualScrollVisibleIndexs.start && normalEndCell.rowIndex < virtualScrollVisibleIndexs.start) || (currentCell.rowIndex > virtualScrollVisibleIndexs.end && normalEndCell.rowIndex > virtualScrollVisibleIndexs.end) ) { result = false } } } } return result }, // show corner showCorner() { let result = true const { cellAutofillOption } = this if (cellAutofillOption) { const { directionX, directionY } = this.cellAutofillOption if ( isBoolean(directionY) && !directionY && isBoolean(directionX) && !directionX ) { result = false } } else { result = false } return result }, // corner cell info cornerCellInfo() { const { allRowKeys, colgroups, cellSelectionRangeData } = this const { rightColKey, bottomRowKey } = cellSelectionRangeData let isLastColumn = false if (isLastColumnByColKey(rightColKey, colgroups)) { isLastColumn = true } else { const index = colgroups.findIndex((x) => x.key === rightColKey) // right col is right fixed and current col is not right fixed if ( colgroups[index + 1].fixed === COLUMN_FIXED_TYPE.RIGHT && colgroups[index].fixed !== COLUMN_FIXED_TYPE.RIGHT ) { isLastColumn = true } } let isLastRow = false if (isLastRowByRowKey(bottomRowKey, allRowKeys)) { isLastRow = true } return { isLastColumn, isLastRow, } }, // is first selection row isFirstSelectionRow() { const { allRowKeys, cellSelectionRangeData } = this return allRowKeys[0] === cellSelectionRangeData.topRowKey }, // is first selection column isFirstSelectionCol() { const { colgroups, cellSelectionRangeData } = this return colgroups[0].key === cellSelectionRangeData.leftColKey }, // is first not fixed selection column isFirstNotFixedSelectionCol() { let result = false const { colgroups, cellSelectionRangeData } = this if (colgroups.find((x) => x.fixed === 'left')) { const col = colgroups.find((x) => !x.fixed) if (col && col.field === cellSelectionRangeData.leftColKey) { result = true } } return result }, }, watch: { parentRendered: { handler: function (val) { if (val) { // add table container scroll hook this.hooks.addHook( HOOKS_NAME.TABLE_CONTAINER_SCROLL, () => { this.setCellEls() this.debounceSetCellEls() this.resetCellPositions() // debounce reset cell positions this.debounceResetCellPositions() }, ) // add table size change hook this.hooks.addHook(HOOKS_NAME.TABLE_SIZE_CHANGE, () => { // debounce reset cell positions this.debounceResetCellPositions() }) // add table td width change hook this.hooks.addHook( HOOKS_NAME.TABLE_CELL_WIDTH_CHANGE, () => { this.$nextTick(() => { this.resetCellPositions() }) }, ) // add clipboard cell value change hook this.hooks.addHook( HOOKS_NAME.CLIPBOARD_CELL_VALUE_CHANGE, () => { this.$nextTick(() => { this.resetCellPositions() }) }, ) } }, immediate: true, }, // watch current cell 'cellSelectionData.currentCell': { handler: function (val) { const { rowKey, colKey } = val if (!isEmptyValue(rowKey) && !isEmptyValue(colKey)) { this.setCurrentCellEl() this.setSelectionPositions({ type: 'currentCell' }) } else { this[INSTANCE_METHODS.CLEAR_CURRENT_CELL_RECT]() } this.setCellSelectionRangeData() }, deep: true, immediate: true, }, // watch normal end cell 'cellSelectionData.normalEndCell': { handler: function (val) { const { rowKey, colKey } = val if (!isEmptyValue(rowKey) && !isEmptyValue(colKey)) { // set normal end cell el this.setNormalEndCellEl() this.setSelectionPositions({ type: 'normalEndCell' }) } else { this[INSTANCE_METHODS.CLEAR_NORMAL_END_CELL_RECT]() } this.setCellSelectionRangeData() }, deep: true, immediate: true, }, // watch autofill cell 'cellSelectionData.autoFillEndCell': { handler: function (val) { const { rowKey, colKey } = val if (!isEmptyValue(rowKey) && !isEmptyValue(colKey)) { this.setAutofillEndCellEl() this.setSelectionPositions({ type: 'autoFillEndCell' }) } else { this.clearAutofillEndCellRect() } }, deep: true, immediate: true, }, }, created() { // debounce reset cell positions this.debounceResetCellPositions = debounce( this.resetCellPositions, 210, ) // debounce set cell els this.debounceSetCellEls = debounce(this.setCellEls, 200) }, methods: { // reset cell position resetCellPositions() { const { currentCell, normalEndCell } = this.cellSelectionData if ( !isEmptyValue(currentCell.rowKey) && !isEmptyValue(currentCell.colKey) ) { this.setSelectionPositions({ type: 'currentCell', }) } if ( !isEmptyValue(normalEndCell.rowKey) && !isEmptyValue(normalEndCell.colKey) ) { this.setSelectionPositions({ type: 'normalEndCell', }) } }, // set cell els setCellEls() { if (this.isVirtualScroll && this.selectionBordersVisibility) { this.setCurrentCellEl() this.setNormalEndCellEl() } }, // set cell selection range data setCellSelectionRangeData() { const { currentCellSelectionType } = this const { currentCell, normalEndCell } = this.cellSelectionData let result = {} if ( currentCellSelectionType === CURRENT_CELL_SELECTION_TYPES.SINGLE ) { result = { leftColKey: currentCell.colKey, rightColKey: currentCell.colKey, topRowKey: currentCell.rowKey, bottomRowKey: currentCell.rowKey, } } else if ( currentCellSelectionType === CURRENT_CELL_SELECTION_TYPES.RANGE ) { const leftmostColKey = getLeftmostColKey({ colgroups: this.colgroups, colKeys: [currentCell.colKey, normalEndCell.colKey], }) /* current cell col key is leftmost colKey 需要用 colKey 的位置进行判断,不能根据当前单元格 left 值判断(固定列时) */ if (leftmostColKey === currentCell.colKey) { result.leftColKey = currentCell.colKey result.rightColKey = normalEndCell.colKey } else { result.leftColKey = normalEndCell.colKey result.rightColKey = currentCell.colKey } if (currentCell.rowIndex < normalEndCell.rowIndex) { result.topRowKey = currentCell.rowKey result.bottomRowKey = normalEndCell.rowKey } else { result.topRowKey = normalEndCell.rowKey result.bottomRowKey = currentCell.rowKey } } else { // clear result = { leftColKey: '', rightColKey: '', topRowKey: '', bottomRowKey: '', } } // this.$emit(EMIT_EVENTS.CELL_SELECTION_RANGE_DATA_CHANGE, result) this.$emit('cellSelectionRangeDataChange', result) }, // get cell position getCellPosition({ cellEl, tableLeft, tableTop }) { if (!this.selectionBordersVisibility) { return false } const { left: cellLeft, top: cellTop, height: cellHeight, width: cellWidth, } = cellEl.getBoundingClientRect() if (cellHeight && cellWidth) { return { left: cellLeft - tableLeft, top: cellTop - tableTop, width: cellWidth, height: cellHeight, } } }, // get cell position by column key getCellPositionByColKey({ tableLeft, tableTop, colKey, isFirstRow, isLastRow, }) { if (!this.selectionBordersVisibility) { return false } let cellEl if (isFirstRow) { cellEl = this.getTableFirstRowCellByColKey(colKey) } else if (isLastRow) { cellEl = this.getTableLastRowCellByColKey(colKey) } if (!cellEl) { return } const { left: cellLeft, top: cellTop, // height: cellHeight, width: cellWidth, } = cellEl.getBoundingClientRect() if (cellWidth) { return { left: cellLeft - tableLeft, top: cellTop - tableTop, width: cellWidth, } } }, // set selection positions setSelectionPositions({ type }) { const { allRowKeys, tableEl, currentCellEl, normalEndCellEl, autoFillEndCellEl, cellSelectionData, virtualScrollVisibleIndexs, } = this // table empty if (allRowKeys.length === 0) { return false } if (!tableEl) { return false } const { left: tableLeft, top: tableTop } = tableEl.getBoundingClientRect() let isCurrentCellOverflow = false let isNormalEndCellOverflow = false // set current cell position if (type === 'currentCell') { isCurrentCellOverflow = true if (currentCellEl) { const rect = this.getCellPosition({ cellEl: currentCellEl, tableLeft, tableTop, }) if (rect) { isCurrentCellOverflow = false this.cellSelectionRect.currentCellRect = rect } } } // set nromal end cell position` if (type === 'normalEndCell') { isNormalEndCellOverflow = true if (normalEndCellEl) { const rect = this.getCellPosition({ cellEl: normalEndCellEl, tableLeft, tableTop, }) if (rect) { isNormalEndCellOverflow = false this.cellSelectionRect.normalEndCellRect = rect } } } // current cell overflow or normal end cell overflow && is virtual scroll if ( (isCurrentCellOverflow || isNormalEndCellOverflow) && this.isVirtualScroll ) { const { currentCell, normalEndCell } = cellSelectionData // 弥补的 let mackUpColKey let mackUpRowIndex if (isCurrentCellOverflow) { mackUpColKey = currentCell.colKey mackUpRowIndex = currentCell.rowIndex } else { mackUpColKey = normalEndCell.colKey mackUpRowIndex = normalEndCell.rowIndex } let mackUpRect /* 当没有 currentCellRect 或 normalCellRect 时 进行纠正,否则只更新top值 */ if ( (isCurrentCellOverflow && !this.cellSelectionRect.currentCellRect.height) || (isNormalEndCellOverflow && !this.cellSelectionRect.normalEndCellRect.height) ) { const mackUpRectParams = { tableLeft, tableTop, colKey: mackUpColKey, } // 上方超出 if (mackUpRowIndex < virtualScrollVisibleIndexs.start) { mackUpRect = this.getCellPositionByColKey({ ...mackUpRectParams, isFirstRow: true, }) } else if (mackUpRowIndex > virtualScrollVisibleIndexs.end) { // 下方超出 mackUpRect = this.getCellPositionByColKey({ ...mackUpRectParams, isLastRow: true, }) } } else { // 仅更新 top 值 // 上方超出 if (mackUpRowIndex < virtualScrollVisibleIndexs.start) { mackUpRect = { top: 0, } } else if (mackUpRowIndex > virtualScrollVisibleIndexs.end) { // 下方超出 mackUpRect = { top: tableEl.clientHeight, } } } if (isCurrentCellOverflow) { Object.assign( this.cellSelectionRect.currentCellRect, mackUpRect, ) } else { Object.assign( this.cellSelectionRect.normalEndCellRect, mackUpRect, ) } } if (autoFillEndCellEl && type === 'autoFillEndCell') { const rect = this.getCellPosition({ cellEl: autoFillEndCellEl, tableLeft, tableTop, }) if (rect) { this.cellSelectionRect.autoFillEndCellRect = rect } } }, /* get selection current 1、selection current 2、auto fill area */ getSelectionCurrent({ fixedType }) { const result = { selectionCurrent: null, autoFillArea: null, } const { cellSelectionRect, colgroups, cellSelectionData } = this const { currentCellRect, normalEndCellRect } = cellSelectionRect if (!currentCellRect.width) { return result } const borders = { borderWidth: currentCellRect.width + 1, borderHeight: currentCellRect.height, topBorder: { show: true, width: 0, height: 2, top: currentCellRect.top - 1, left: currentCellRect.left - 1, }, rightBorder: { show: true, width: 2, height: 0, top: currentCellRect.top, left: currentCellRect.left + currentCellRect.width - 2, }, bottomBorder: { show: true, width: 0, height: 2, top: currentCellRect.top + currentCellRect.height - 2, left: currentCellRect.left - 1, }, leftBorder: { show: true, width: 2, height: 0, top: currentCellRect.top, left: currentCellRect.left - 1, }, corner: { show: !normalEndCellRect.width, top: 0, left: 0, }, } borders.corner.top = borders.bottomBorder.top - 3 borders.corner.left = borders.rightBorder.left - 3 // cell selection single autofill if (!normalEndCellRect.width) { result.autoFillArea = this.getSelectionAutofillArea({ areaPostions: borders, fixedType, }) } const totalColKeys = [cellSelectionData.currentCell.colKey] const fixedColKeys = getColKeysByFixedTypeWithinColKeys({ colKeys: totalColKeys, fixedType, colgroups, }) result.selectionCurrent = this.getBorders({ ...borders, showCorner: !normalEndCellRect.width, className: 'selection-current', fixedType, totalColKeys, fixedColKeys, }) return result }, /* get selection areas 1、normal area 2、auto fill area */ getSelectionAreas({ fixedType }) { const result = { normalArea: null, autoFillArea: null, } const { currentCell, normalEndCell } = this.cellSelectionData const { cellSelectionRect, cellSelectionRangeData, colgroups } = this const { currentCellRect, normalEndCellRect } = cellSelectionRect if (!currentCellRect.width || !normalEndCellRect.width) { return result } const borders = { borderWidth: 0, borderHeight: 0, topBorder: { show: true, width: 0, height: 1, top: 0, left: 0, }, rightBorder: { show: true, width: 1, height: 0, top: 0, left: 0, }, bottomBorder: { show: true, width: 0, height: 1, top: 0, left: 0, }, leftBorder: { show: true, width: 1, height: 0, top: 0, left: 0, }, corner: { show: true, top: 0, left: 0, }, } const leftmostColKey = getLeftmostColKey({ colgroups: this.colgroups, colKeys: [currentCell.colKey, normalEndCell.colKey], }) // end cell column key right if (leftmostColKey === currentCell.colKey) { borders.borderWidth = normalEndCellRect.left - currentCellRect.left + normalEndCellRect.width + 1 borders.topBorder.left = currentCellRect.left - 1 borders.bottomBorder.left = currentCellRect.left - 1 borders.leftBorder.left = currentCellRect.left - 1 borders.rightBorder.left = normalEndCellRect.left + normalEndCellRect.width - 1 } else if (leftmostColKey === normalEndCell.colKey) { // end cell column key left or equal borders.borderWidth = currentCellRect.left - normalEndCellRect.left + currentCellRect.width + 1 borders.topBorder.left = normalEndCellRect.left - 1 borders.rightBorder.left = currentCellRect.left + currentCellRect.width - 1 borders.bottomBorder.left = normalEndCellRect.left - 1 borders.leftBorder.left = normalEndCellRect.left - 1 } // end cell below if (normalEndCellRect.top > currentCellRect.top) { borders.borderHeight = normalEndCellRect.top - currentCellRect.top + normalEndCellRect.height borders.topBorder.top = currentCellRect.top - 1 borders.rightBorder.top = currentCellRect.top borders.bottomBorder.top = normalEndCellRect.top + normalEndCellRect.height - 1 borders.leftBorder.top = currentCellRect.top } else if (normalEndCellRect.top <= currentCellRect.top) { // end cell above or equal borders.borderHeight = currentCellRect.top - normalEndCellRect.top + currentCellRect.height borders.topBorder.top = normalEndCellRect.top - 1 borders.rightBorder.top = normalEndCellRect.top borders.bottomBorder.top = currentCellRect.top + currentCellRect.height - 1 borders.leftBorder.top = normalEndCellRect.top } borders.corner.top = borders.bottomBorder.top - 4 borders.corner.left = borders.rightBorder.left - 4 if (normalEndCellRect.width) { result.autoFillArea = this.getSelectionAutofillArea({ areaPostions: borders, fixedType, }) } const { leftColKey, rightColKey } = cellSelectionRangeData const totalColKeys = getColKeysByRangeColKeys({ colKey1: leftColKey, colKey2: rightColKey, colgroups, }) const fixedColKeys = getColKeysByFixedTypeWithinColKeys({ colKeys: totalColKeys, fixedType, colgroups, }) result.normalArea = this.getBorders({ ...borders, className: 'selection-normal-area', fixedType, totalColKeys, fixedColKeys, }) result.normalAreaLayer = this.getAreaLayer({ ...borders, className: 'selection-normal-area-layer', fixedType, totalColKeys, fixedColKeys, }) return result }, // get selection auto fill getSelectionAutofillArea({ areaPostions, fixedType }) { let result = null const { cellAutofillOption, cellSelectionRangeData, cellSelectionRect, cellSelectionData, isAutofillStarting, currentCellSelectionType, colgroups, } = this if (!isAutofillStarting) { return result } const { currentCellRect, autoFillEndCellRect } = cellSelectionRect if (!currentCellRect.width || !autoFillEndCellRect.width) { return result } if (!areaPostions) { return result } const borders = { borderWidth: 0, borderHeight: 0, topBorder: { show: true, width: 0, height: 1, top: 0, left: 0, }, rightBorder: { show: true, width: 1, height: 0, top: 0, left: 0, }, bottomBorder: { show: true, width: 0, height: 1, top: 0, left: 0, }, leftBorder: { show: true, width: 1, height: 0, top: 0, left: 0, }, corner: { show: false, top: 0, left: 0, }, } const { currentCell, autoFillEndCell } = cellSelectionData let { leftColKey, rightColKey } = cellSelectionRangeData if ( currentCellSelectionType === CURRENT_CELL_SELECTION_TYPES.SINGLE ) { leftColKey = currentCell.colKey rightColKey = currentCell.colKey } let leftmostColKey if (leftColKey !== autoFillEndCell.colKey) { leftmostColKey = getLeftmostColKey({ colgroups, colKeys: [leftColKey, autoFillEndCell.colKey], }) } let rightmostColKey if (rightColKey !== autoFillEndCell.colKey) { rightmostColKey = getRightmostColKey({ colgroups, colKeys: [rightColKey, autoFillEndCell.colKey], }) } // autofilling direction let autofillingDirection let rangeColKey1 let rangeColKey2 // auto fill end cell below if (autoFillEndCellRect.top > areaPostions.bottomBorder.top) { autofillingDirection = AUTOFILLING_DIRECTION.DOWN rangeColKey1 = leftColKey rangeColKey2 = rightColKey borders.topBorder.show = false borders.borderWidth = areaPostions.borderWidth borders.borderHeight = autoFillEndCellRect.top - areaPostions.bottomBorder.top + autoFillEndCellRect.height borders.rightBorder.top = areaPostions.bottomBorder.top borders.rightBorder.left = areaPostions.rightBorder.left if ( currentCellSelectionType === CURRENT_CELL_SELECTION_TYPES.SINGLE ) { borders.rightBorder.left++ } borders.leftBorder.top = areaPostions.bottomBorder.top borders.leftBorder.left = areaPostions.leftBorder.left borders.bottomBorder.top = autoFillEndCellRect.top + autoFillEndCellRect.height - 1 borders.bottomBorder.left = areaPostions.bottomBorder.left } else if (autoFillEndCellRect.top < areaPostions.topBorder.top) { // end cell above autofillingDirection = AUTOFILLING_DIRECTION.UP rangeColKey1 = leftColKey rangeColKey2 = rightColKey borders.bottomBorder.show = false borders.borderWidth = areaPostions.borderWidth borders.borderHeight = areaPostions.topBorder.top - autoFillEndCellRect.top borders.topBorder.top = autoFillEndCellRect.top - 1 borders.topBorder.left = areaPostions.topBorder.left borders.rightBorder.top = autoFillEndCellRect.top borders.rightBorder.left = areaPostions.rightBorder.left if ( currentCellSelectionType === CURRENT_CELL_SELECTION_TYPES.SINGLE ) { borders.rightBorder.left++ } borders.leftBorder.top = autoFillEndCellRect.top borders.leftBorder.left = areaPostions.leftBorder.left } else if (rightmostColKey === autoFillEndCell.colKey && !isEmptyValue(rightmostColKey)) { // auto fill end cell right autofillingDirection = AUTOFILLING_DIRECTION.RIGHT rangeColKey1 = getNextColKey({ colgroups, currentColKey: rightColKey, }) rangeColKey2 = autoFillEndCell.colKey borders.leftBorder.show = false borders.borderWidth = autoFillEndCellRect.left - areaPostions.rightBorder.left + autoFillEndCellRect.width + 1 borders.borderHeight = areaPostions.borderHeight borders.topBorder.top = areaPostions.topBorder.top borders.topBorder.left = areaPostions.rightBorder.left - 1 borders.rightBorder.top = areaPostions.topBorder.top borders.rightBorder.left = autoFillEndCellRect.left + autoFillEndCellRect.width - 1 borders.bottomBorder.top = areaPostions.bottomBorder.top borders.bottomBorder.left = areaPostions.rightBorder.left - 1 } else if (leftmostColKey === autoFillEndCell.colKey && !isEmptyValue(leftmostColKey)) { // auto fill end cell left autofillingDirection = AUTOFILLING_DIRECTION.LEFT rangeColKey1 = getPreviewColKey({ colgroups, currentColKey: leftColKey, }) rangeColKey2 = autoFillEndCell.colKey borders.rightBorder.show = false borders.borderWidth = areaPostions.leftBorder.left - autoFillEndCellRect.left + 1 borders.borderHeight = areaPostions.borderHeight borders.topBorder.top = areaPostions.topBorder.top borders.topBorder.left = autoFillEndCellRect.left borders.rightBorder.left = areaPostions.topBorder.left borders.bottomBorder.top = areaPostions.bottomBorder.top borders.bottomBorder.left = autoFillEndCellRect.left borders.leftBorder.top = areaPostions.topBorder.top borders.leftBorder.left = autoFillEndCellRect.left } else { return result } const { directionX, directionY } = cellAutofillOption if (isBoolean(directionX) && !directionX) { if ( autofillingDirection === AUTOFILLING_DIRECTION.LEFT || autofillingDirection === AUTOFILLING_DIRECTION.RIGHT ) { return false } } if (isBoolean(directionY) && !directionY) { if ( autofillingDirection === AUTOFILLING_DIRECTION.UP || autofillingDirection === AUTOFILLING_DIRECTION.DOWN ) { return false } } const totalColKeys = getColKeysByRangeColKeys({ colKey1: rangeColKey1, colKey2: rangeColKey2, colgroups, }) const fixedColKeys = getColKeysByFixedTypeWithinColKeys({ colKeys: totalColKeys, fixedType, colgroups, }) result = this.getBorders({ className: 'selection-autofill-area', ...borders, fixedType, totalColKeys, fixedColKeys, }) if (result) { this.eventCenter.emit( GLOBAL_EVENT.AUTOFILLING_DIRECTION_CHANGE, autofillingDirection, ) } return result }, // get borders getBorders({ borderWidth, borderHeight, topBorder, rightBorder, bottomBorder, leftBorder, corner, className, fixedType, totalColKeys, fixedColKeys, }) { const { cornerCellInfo, colgroups, isFirstSelectionRow, isFirstSelectionCol, isFirstNotFixedSelectionCol, showCorner, } = this let isRender = true if (fixedType) { isRender = isExistGivenFixedColKey({ fixedType, colKeys: totalColKeys, colgroups, }) } else { // middle normal area isRender = isExistNotFixedColKey({ colKeys: totalColKeys, colgroups, }) } if (!isRender) { return null } // fixed columns total width let fixedColsTotalWidth = 0 if (fixedColKeys.length) { fixedColsTotalWidth = getTotalWidthByColKeys({ colKeys: fixedColKeys, colgroups, }) console.log('🚀 ~ fixedColsTotalWidth:', fixedColsTotalWidth) } if (fixedType) { borderWidth = fixedColsTotalWidth if (fixedType === COLUMN_FIXED_TYPE.LEFT) { borderWidth += 1 } } if (fixedType === COLUMN_FIXED_TYPE.LEFT) { if (totalColKeys.length !== fixedColKeys.length) { rightBorder.show = false corner.show = false } } if (fixedType === COLUMN_FIXED_TYPE.RIGHT) { if (totalColKeys.length !== fixedColKeys.length) { leftBorder.show = false } topBorder.left = rightBorder.left - borderWidth + 1 bottomBorder.left = rightBorder.left - borderWidth + 1 } // solved first row、first column、first not fixed column selection border hidden if (isFirstSelectionRow) { topBorder.top += 1 } if (isFirstSelectionCol) { leftBorder.left += 1 } if (isFirstNotFixedSelectionCol) { leftBorder.left += 1 } let cornerTop = corner.top let cornerLeft = corner.left let cornerBorderRightWidth = '1px' let cornerBorderBottomtWidth = '1px' if (cornerCellInfo.isLastRow) { cornerTop -= 3 cornerBorderBottomtWidth = '0px' } if (cornerCellInfo.isLastColumn) { cornerLeft -= 3 cornerBorderRightWidth = '0px' } if (!showCorner) { corner.show = false } // corner props const cornerProps = { class: clsName('selection-corner'), style: { display: corner.show ? 'block' : 'none', top: cornerTop + 'px', left: cornerLeft + 'px', borderWidth: `1px ${cornerBorderRightWidth} ${cornerBorderBottomtWidth} 1px`, }, onMousedown: (e) => { this.eventCenter.emit(GLOBAL_EVENT.SELECTION_CORNER_MOUSEDOWN, { event: e, }, ) }, onMouseup: (e) => { this.eventCenter.emit(GLOBAL_EVENT.SELECTION_CORNER_MOUSEUP, { event: e, }, ) }, } const calcBorderWidth = rightBorder.left - leftBorder.left + 2 return ( <div class={clsName(className)}> {/* top */} <div style={{ display: topBorder.show ? 'block' : 'none', width: calcBorderWidth + 'px', height: topBorder.height + 'px', top: topBorder.top + 'px', left: topBorder.left + 'px', }} class={clsName('selection-border')} ></div> {/* right */} <div style={{ display: rightBorder.show ? 'block' : 'none', width: rightBorder.width + 'px', height: borderHeight + 'px', top: rightBorder.top + 'px', left: rightBorder.left + 'px', }} class={clsName('selection-border')} ></div> {/* bottom */} <div style={{ display: bottomBorder.show ? 'block' : 'none', width: calcBorderWidth + 'px', height: bottomBorder.height + 'px', top: bottomBorder.top + 'px', left: bottomBorder.left + 'px', }} class={clsName('selection-border')} ></div> {/* left */} <div style={{ display: leftBorder.show ? 'block' : 'none', width: leftBorder.width + 'px', height: borderHeight + 'px', top: leftBorder.top + 'px', left: leftBorder.left + 'px', }} class={clsName('selection-border')} ></div> {/* corner */} {<div {...cornerProps}></div>} </div> ) }, // get area rect getAreaLayer({ borderWidth, borderHeight, topBorder, className, fixedType, totalColKeys, fixedColKeys, }) { const { colgroups } = this let isRender = true if (fixedType) { isRender = isExistGivenFixedColKey({ fixedType, colKeys: totalColKeys, colgroups, }) } else { // middle normal area isRender = isExistNotFixedColKey({ colKeys: totalColKeys, colgroups, }) } if (!isRender) { return null } // fixed columns total width let fixedColsTotalWidth = 0 if (fixedColKeys.length) { fixedColsTotalWidth = getTotalWidthByColKeys({ colKeys: fixedColKeys, colgroups, }) } if (fixedType) { borderWidth = fixedColsTotalWidth if (fixedType === COLUMN_FIXED_TYPE.LEFT) { borderWidth += 1 } } return ( <div class={clsName(className)} style={{ top: topBorder.top + 'px', left: topBorder.left + 'px', width: borderWidth + 'px', height: borderHeight + 'px', }} ></div> ) }, /* get table first row cell by col key 用作跨页单元格选择,表格大小变化或者存在横向滚动条时,区域选择位置自动校准 */ getTableFirstRowCellByColKey(colKey) { let result = null const { tableEl } = this if (tableEl) { result = tableEl.querySelector( `tbody.fan-table-body tr td[col-key="${colKey}"]`, ) } return result }, /* get table last row cell by col key 用作跨页单元格选择,表格大小变化或者存在横向滚动条时,区域选择位置自动校准 */ getTableLastRowCellByColKey(colKey) { let result = null const { tableEl } = this if (tableEl) { result = tableEl.querySelector( `tbody.fan-table-body tr:last-child td[col-key="${colKey}"]`, ) } return result }, // get table el getTableCellEl({ rowKey, colKey }) { let result = null const { tableEl } = this if (tableEl) { result = tableEl.querySelector( `tbody.fan-table-body tr[row-key="${rowKey}"] td[col-key="${colKey}"]`, ) } return result }, // set current cell el setCurrentCellEl() { const { cellSelectionData } = this const { rowKey, colKey } = cellSelectionData.currentCell if (!isEmptyValue(rowKey) && !isEmptyValue(colKey)) { const cellEl = this.getTableCellEl({ rowKey, colKey, }) if (cellEl) { this.currentCellEl = cellEl } } }, // set normal end cell el setNormalEndCellEl() { const { cellSelectionData } = this const { rowKey, colKey } = cellSelectionData.normalEndCell if (!isEmptyValue(rowKey) && !isEmptyValue(colKey)) { const cellEl = this.getTableCellEl({ rowKey, colKey, }) if (cellEl) { this.normalEndCellEl = cellEl } } }, // set auto fill cell el setAutofillEndCellEl() { const { cellSelectionData, tableEl } = this const { rowKey, colKey } = cellSelectionData.autoFillEndCell if (tableEl) { const autoFillEndCellEl = tableEl.querySelector( `tbody.fan-table-body tr[row-key="${rowKey}"] td[col-key="${colKey}"]`, ) if (autoFillEndCellEl) { this.autoFillEndCellEl = autoFillEndCellEl } } }, // clear auto fill end cell rect clearAutofillEndCellRect() { this.autoFillEndCellEl = null this.cellSelectionRect.autoFillEndCellRect = { left: 0, top: 0, width: 0, height: 0, } }, // clear current cell rect [INSTANCE_METHODS.CLEAR_CURRENT_CELL_RECT]() { this.currentCellEl = null this.cellSelectionRect.currentCellRect = { left: 0, top: 0, width: 0, height: 0, } }, // clear normal end cell rect [INSTANCE_METHODS.CLEAR_NORMAL_END_CELL_RECT]() { this.normalEndCellEl = null this.cellSelectionRect.normalEndCellRect = { left: 0, top: 0, width: 0, height: 0, } }, }, render() { if (!this.selectionBordersVisibility) { return null } // fixed left const fixedLeftSelectionCurrent = this.getSelectionCurrent({ fixedType: COLUMN_FIXED_TYPE.LEFT, }) const fixedLeftSelectionArea = this.getSelectionAreas({ fixedType: COLUMN_FIXED_TYPE.LEFT, }) const fixedLeftAutoFillArea = fixedLeftSelectionCurrent.autoFillArea || fixedLeftSelectionArea.autoFillArea // middle const middleSelectionCurrent = this.getSelectionCurrent({ fixedType: '', }) const middleSelectionArea = this.getSelectionAreas({ fixedType: '', }) const middleAutoFillArea = middleSelectionCurrent.autoFillArea || middleSelectionArea.autoFillArea // fixed right const fixedRightSelectionCurrent = this.getSelectionCurrent({ fixedType: COLUMN_FIXED_TYPE.RIGHT, }) const fixedRightSelectionArea = this.getSelectionAreas({ fixedType: COLUMN_FIXED_TYPE.RIGHT, }) const fixedRightAutoFillArea = fixedRightSelectionCurrent.autoFillArea || fixedRightSelectionArea.autoFillArea return ( <div class={clsName('selection-wrapper')} style={{ visibility: this.isCellEditing ? 'hidden' : '' }} > <div class={clsName('selection-fixed-left')}> {/* current */} {fixedLeftSelectionCurrent.selectionCurrent} {/* area */} {fixedLeftSelectionArea.normalArea} {/* auto fill */} {fixedLeftAutoFillArea} {/* area layer */} {fixedLeftSelectionArea.normalAreaLayer} </div> <div class={clsName('selection-middle')}> {/* current */} {middleSelectionCurrent.selectionCurrent} {/* area */} {middleSelectionArea.normalArea} {/* auto fill */} {middleAutoFillArea} {/* area layer */} {middleSelectionArea.normalAreaLayer} </div> <div class={clsName('selection-fixed-right')}> {/* current */} {fixedRightSelectionCurrent.selectionCurrent} {/* area */} {fixedRightSelectionArea.normalArea} {/* auto fill */} {fixedRightAutoFillArea} {/* area layer */} {fixedRightSelectionArea.normalAreaLayer} </div> </div> ) }, }