vxe-table-select-area
Version:
一个基于 vxe-table 的可区域选中复制、粘贴的组件
1,759 lines (1,610 loc) • 71.6 kB
JavaScript
/* eslint-disable no-unreachable */
/* eslint-disable brace-style */
// import Vue from 'vue'
import {h} from 'vue'
import XEUtils from 'xe-utils'
import { getMouseEventClickType } from '../utils/mouse-event'
import { getScrollbarWidth } from '../utils/scroll-bar'
import { isEmptyValue, isBoolean, isFunction } from '../utils/index'
import { KEY_CODES, MOUSE_EVENT_CLICK_TYPE } from '../utils/constant'
import {
clsName,
getColumnByColkey,
getColKeysByFixedTypeWithinColKeys,
isExistNotFixedColKey,
isOperationColumn,
getLeftmostColKey,
getRightmostColKey,
getColKeysByRangeColKeys,
getSelectionRangeData,
getNextColKey,
cellAutofill,
isCellInSelectionRange,
isContextmenuPanelClicked,
isClearSelectionByBodyCellRightClick,
getPreviewColKey,
isLastColumnByColKey,
isLastRowByRowKey,
isExistGivenFixedColKey,
getTotalWidthByColKeys
} from '../common'
import {
onBeforeCopy,
onAfterCopy,
onBeforePaste,
onAfterPaste,
onBeforeCut,
onAfterCut,
onBeforeDelete,
onAfterDelete
} from '../common/clipboard'
import {
INSTANCE_METHODS,
COMPS_CUSTOM_ATTRS,
COLUMN_FIXED_TYPE,
CURRENT_CELL_SELECTION_TYPES,
EMIT_EVENTS,
COMPS_NAME,
AUTOFILLING_DIRECTION,
CELL_SELECTION_DIRECTION
} from '../common/constant'
// const { render } = require('nprogress')
import { isInputKeyCode } from '../utils/event-key-codes'
// const vm = new Vue()
// console.log(vm.$createElement);
// console.log(createElement)
// const h = vm.$createElement
// const h = createElement
export default {
name: 'VxeSelection',
data () {
return {
currentCellEl: null,
isBodyCellMousedown: false,
cellSelectionData: {
currentCell: {
rowKey: '',
colKey: '',
rowIndex: -1
},
normalEndCell: {
rowKey: '',
colKey: '',
rowIndex: -1
},
autoFillEndCell: {
rowKey: '',
colKey: ''
}
},
cellSelectionRangeData: {
leftColKey: '',
rightColKey: '',
topRowKey: '',
bottomRowKey: ''
},
// body indicator rowKeys
bodyIndicatorRowKeys: {
startRowKey: '',
startRowKeyIndex: -1,
endRowKey: '',
endRowKeyIndex: -1
},
tableContainerRef: '$el',
tableContentWrapperRef: 'tableBody',
colgroups: [],
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
}
},
domRect: {},
currentCellSelectionType: '',
isAutofillStarting: false,
isColumnResizing: false,
enableStopEditing: true
}
},
computed: {
// return row keys
allRowKeys () {
let result = []
const { keyField } = this.rowOpts
this.rowKeyFieldName = keyField
const { tableData, rowKeyFieldName } = this
if (rowKeyFieldName) {
result = tableData.map((x) => {
return x[rowKeyFieldName]
})
}
// // console.log(480,tableData,rowKeyFieldName,result)
return result
},
/*
enable cell selection
单元格编辑、剪贴板都依赖单元格选择
*/
enableCellSelection () {
let result = true
const { cellSelectionOption, rowKeyFieldName } = this
if (isEmptyValue(rowKeyFieldName)) {
result = false
} else if (
cellSelectionOption &&
isBoolean(cellSelectionOption.enable) &&
cellSelectionOption.enable === false
) {
result = false
}
return result
},
// show corner
showCorner () {
let result = true
// this.cellAutofillOption = true
const { cellAutofillOption } = this
if (cellAutofillOption) {
const { directionX, directionY } = this.cellAutofillOption
if (
isBoolean(directionY) &&
!directionY &&
isBoolean(directionX) &&
!directionX
) {
result = false
}
} else {
result = false
}
// // console.log(163333,cellAutofillOption)
return result
}
},
watch: {
tableColumn: {
handler (newVal) {
this.$nextTick(() => {
// // console.log(105,newVal)
this.tableEl = this.$refs[this.tableContentWrapperRef].$refs.table
this.tableColumn.forEach(e => {
const obj = {
field: e.field || e.id,
edit: true,
key: e.id,
title: e.title || e.type,
width: e.minWidth,
_colspan: e.colSpan,
_keys: e.id,
_level: e.level,
_realTimeWidth: e.renderWidth,
_rowspan: e.rowSpan
}
this.colgroups.push(obj)
})
})
},
immediate: false
},
allRowKeys: {
handler (newVal) {
if (Array.isArray(newVal)) {
const { currentCell } = this.cellSelectionData
// 行被移除,清空单元格选中
if (currentCell.rowIndex > -1) {
if (newVal.indexOf(currentCell.rowKey) === -1) {
this.clearCellSelectionCurrentCell()
}
}
}
},
immediate: false
},
'cellSelectionData.currentCell': {
handler: function (val) {
this.setCurrentCellSelectionType()
const { rowKey, colKey } = val
if (!isEmptyValue(rowKey) && !isEmptyValue(colKey)) {
// // console.log(138)
this.setCurrentCellEl()
this.setSelectionPositions({ type: 'currentCell' })
} else {
this[INSTANCE_METHODS.CLEAR_CURRENT_CELL_RECT]()
}
this.setCellSelectionRangeData()
},
deep: true,
immediate: true
},
'cellSelectionData.normalEndCell': {
handler: function (val) {
this.setCurrentCellSelectionType()
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
},
'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
},
isAutofillStarting: {
handler (val) {
if (!val) {
this.setCellSelectionByAutofill()
this.clearCellSelectionAutofillEndCell()
}
}
}
},
methods: {
setCurrentCellSelectionType () {
const { currentCell, normalEndCell } = this.cellSelectionData
let result
if (
isEmptyValue(currentCell.rowKey) ||
isEmptyValue(currentCell.colKey)
) {
result = ''
} else {
if (
!isEmptyValue(normalEndCell.rowKey) &&
!isEmptyValue(normalEndCell.colKey)
) {
result = CURRENT_CELL_SELECTION_TYPES.RANGE
} else {
result = CURRENT_CELL_SELECTION_TYPES.SINGLE
}
}
// // console.log(261,result)
this.currentCellSelectionType = result
},
resetCellPositions () {
// // // console.log(350)
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'
})
}
},
cellSelectionRangeDataChange (newData) {
this.cellSelectionRangeData = Object.assign(
this.cellSelectionRangeData,
newData
)
},
cellSelectionCornerMousedown ({ event }) {
this.isAutofillStarting = true
},
autofillingDirectionChange (direction) {
this.autofillingDirection = direction
},
cellSelectionCornerMouseup ({ event }) {
this.isAutofillStarting = false
},
handleCellAreaEvent: function handleCellAreaEvent (evnt, params) {
// // // console.log(17,evnt,params)
const { shiftKey } = evnt
const { row, column } = params
const rowData = row
const { getRowid, cellSelectionData, cellSelectionRangeData, colgroups, allRowKeys } = this
const rowKey = getRowid(rowData)
const colKey = column.id
// // console.log(24,this,rowKey)
const { currentCell } = cellSelectionData
const mouseEventClickType = getMouseEventClickType(evnt)
// // console.log(47,mouseEventClickType)
this.isBodyCellMousedown = true
const isClearByRightClick =
isClearSelectionByBodyCellRightClick({
mouseEventClickType,
cellData: {
rowKey,
colKey
},
cellSelectionData,
cellSelectionRangeData,
colgroups,
allRowKeys
})
// // // console.log(70,cellSelectionData,cellSelectionRangeData,colgroups,allRowKeys)
// const isClearByRightClick = true
if (isClearByRightClick) {
// clear header indicator colKeys
// this.clearHeaderIndicatorColKeys();
// clear body indicator colKeys
this.clearBodyIndicatorRowKeys()
if (shiftKey && currentCell.rowIndex > -1) {
this.cellSelectionNormalEndCellChange({
rowKey,
colKey
})
} else {
// cell selection by click
this.cellSelectionByClick({ rowData, column })
this.clearCellSelectionNormalEndCell()
}
}
},
// table click outside
tableClickOutside (e) {
// exclude contextmenu panel clicked
if (isContextmenuPanelClicked(e)) {
return false
}
this.isHeaderCellMousedown = false
this.isBodyCellMousedown = false
this.isBodyOperationColumnMousedown = false
this.isAutofillStarting = false
this.setIsColumnResizing(false)
// clear cell selection
this.clearCellSelectionCurrentCell()
this.clearCellSelectionNormalEndCell()
// clear indicators
// this.clearHeaderIndicatorColKeys();
this.clearBodyIndicatorRowKeys()
// stop editing cell
// this[INSTANCE_METHODS.STOP_EDITING_CELL]();
},
// clear header indicator colKeys
clearHeaderIndicatorColKeys () {
this.headerIndicatorColKeys.startColKey = ''
this.headerIndicatorColKeys.startColKeyIndex = -1
this.headerIndicatorColKeys.endColKey = ''
this.headerIndicatorColKeys.endColKeyIndex = -1
},
clearCellSelectionCurrentCell () {
this.cellSelectionCurrentCellChange({
rowKey: '',
colKey: '',
rowIndex: -1
})
},
setIsColumnResizing (val) {
this.isColumnResizing = val
},
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: ''
}
}
// // console.log(3888888,result)
this.$emit(EMIT_EVENTS.CELL_SELECTION_RANGE_DATA_CHANGE, result)
},
// cell selection by click
cellSelectionByClick ({ rowData, column }) {
// const { rowKeyFieldName } = this;
const { getRowid } = this
// const rowKey = getRowKey(rowData, rowKeyFieldName);
const rowKey = getRowid(rowData)
// set cell selection and column to visible
this[INSTANCE_METHODS.SET_CELL_SELECTION]({
rowKey,
colKey: column.id,
isScrollToRow: false
})
// row to visible
this.rowToVisible(KEY_CODES.ARROW_UP, rowKey)
this.rowToVisible(KEY_CODES.ARROW_DOWN, rowKey)
},
// cell selection end cell change
// cellSelectionNormalEndCellChange({ rowKey, colKey }) {
// this.cellSelectionData.normalEndCell.colKey = colKey;
// this.cellSelectionData.normalEndCell.rowKey = rowKey;
// this.cellSelectionData.normalEndCell.rowIndex =
// this.allRowKeys.indexOf(rowKey);
// },
setAutofillEndCellEl () {
const { cellSelectionData, tableEl } = this
const { rowKey, colKey } = cellSelectionData.autoFillEndCell
if (tableEl) {
const autoFillEndCellEl = tableEl.querySelector(
`tbody tr[rowid="${rowKey}"] td[colid="${colKey}"]`
)
if (autoFillEndCellEl) {
this.autoFillEndCellEl = autoFillEndCellEl
}
}
},
[INSTANCE_METHODS.SET_CELL_SELECTION] ({
rowKey,
colKey,
isScrollToRow = true
}) {
const { enableCellSelection } = this
// // console.log(165,this)
// if (!enableCellSelection) {
// return false;
// }
if (!isEmptyValue(rowKey) && !isEmptyValue(colKey)) {
// // console.log(171)
this.cellSelectionCurrentCellChange({
rowKey,
colKey
})
const column = getColumnByColkey(colKey, this.colgroups)
// // console.log(219,this.colgroups,column)
// column to visible
// this.columnToVisible(column);
// row to visible
if (isScrollToRow) {
this[INSTANCE_METHODS.SCROLL_TO_ROW_KEY]({ rowKey })
}
}
},
// table scroll to rowKey position
[INSTANCE_METHODS.SCROLL_TO_ROW_KEY] ({ rowKey }) {
// // console.log('550滚动')
if (isEmptyValue(rowKey)) {
// console.warn("Row key can't be empty!");
return false
}
let scrollTop = 0
const { isVirtualScroll, headerTotalHeight } = this
const tableContainerRef = this.$refs[this.tableContainerRef]
if (isVirtualScroll) {
const position = this.virtualScrollPositions.find(
(x) => x.rowKey === rowKey
)
if (position) {
scrollTop = position.top
}
// fix bug #470
setTimeout(() => {
scrollTo(tableContainerRef, {
top: scrollTop,
behavior: 'auto'
})
}, 200)
} else {
const rowEl = this.$el.querySelector(
`tbody tr[${COMPS_CUSTOM_ATTRS.BODY_ROW_KEY}="${rowKey}"]`
)
scrollTop = rowEl.offsetTop - headerTotalHeight
}
scrollTo(tableContainerRef, {
top: scrollTop,
behavior: isVirtualScroll ? 'auto' : 'smooth'
})
},
// clear current cell rect
[INSTANCE_METHODS.CLEAR_CURRENT_CELL_RECT] () {
this.currentCellEl = null
this.cellSelectionRect.currentCellRect = {
left: 0,
top: 0,
width: 0,
height: 0
}
},
/*
* @rowToVisible
* @desc row to visible
* @param {number} keyCode - current keyCode
* @param {any} nextRowKey - next row key
*/
rowToVisible (keyCode, nextRowKey) {
// const tableContainerRef = this.$refs[this.tableContainerRef];
const tableContainerRef = this[this.tableContainerRef]
const tableContentWrapperRef =
this.$refs[this.tableContentWrapperRef].$refs.table
const { isVirtualScroll, headerTotalHeight, footerTotalHeight } =
this
const {
clientHeight: containerClientHeight,
scrollTop: containerScrollTop
} = tableContainerRef
const nextRowEl = this.$el.querySelector(
`tbody tr[${COMPS_CUSTOM_ATTRS.BODY_ROW_KEY}="${nextRowKey}"]`
)
// // console.log(208,nextRowEl)
if (nextRowEl) {
const { offsetTop: trOffsetTop, clientHeight: trClientHeight } =
nextRowEl
const parentOffsetTop = tableContentWrapperRef.offsetTop
// arrow up
if (keyCode === KEY_CODES.ARROW_UP) {
let diff = 0
if (isVirtualScroll) {
diff =
headerTotalHeight -
(trOffsetTop -
(containerScrollTop - parentOffsetTop))
} else {
diff =
containerScrollTop +
headerTotalHeight -
trOffsetTop
}
if (diff > 0) {
tableContainerRef.scrollTop = containerScrollTop - diff
}
}
// arrow down
else if (keyCode === KEY_CODES.ARROW_DOWN) {
// console.log(652)
let diff = 0
if (isVirtualScroll) {
diff =
trOffsetTop -
(containerScrollTop - parentOffsetTop) +
trClientHeight +
footerTotalHeight -
containerClientHeight
} else {
diff =
trOffsetTop +
trClientHeight +
footerTotalHeight -
(containerClientHeight + containerScrollTop)
}
if (diff >= 0) {
tableContainerRef.scrollTop = containerScrollTop + diff
}
}
const { currentCell } = this.cellSelectionData
// // console.log(258,currentCell)
this.cellSelectionCurrentCellChange({
rowKey: nextRowKey,
colKey: currentCell.colKey
})
}
},
// cell selection current cell change
cellSelectionCurrentCellChange ({ rowKey, colKey }) {
// // console.log(266,this.cellSelectionData)
this.cellSelectionData.currentCell.colKey = colKey
this.cellSelectionData.currentCell.rowKey = rowKey
this.cellSelectionData.currentCell.rowIndex =
this.allRowKeys.indexOf(rowKey)
},
// clear cell selection normal end cell
clearCellSelectionNormalEndCell () {
this.cellSelectionNormalEndCellChange({
rowKey: '',
colKey: '',
rowIndex: -1
})
},
// cell selection end cell change
cellSelectionNormalEndCellChange ({ rowKey, colKey }) {
this.cellSelectionData.normalEndCell.colKey = colKey
this.cellSelectionData.normalEndCell.rowKey = rowKey
this.cellSelectionData.normalEndCell.rowIndex =
this.allRowKeys.indexOf(rowKey)
},
// cell selection auto fill cell change
cellSelectionAutofillCellChange ({ rowKey, colKey }) {
this.cellSelectionData.autoFillEndCell.colKey = colKey
this.cellSelectionData.autoFillEndCell.rowKey = rowKey
},
clearBodyIndicatorRowKeys () {
this.bodyIndicatorRowKeys.startRowKey = ''
this.bodyIndicatorRowKeys.startRowKeyIndex = -1
this.bodyIndicatorRowKeys.endRowKey = ''
this.bodyIndicatorRowKeys.endRowKeyIndex = -1
},
// 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
}
// // console.log(448,cellEl)
}
},
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 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
})
this.domRect = rect
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
})
// // console.log('区域>>>',this.cellSelectionRect,rect)
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
})
}
}
// 仅更新 top 值
else {
// 上方超出
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 cell position
getCellPosition ({ cellEl, tableLeft, tableTop }) {
// // console.log('点击单元格',cellEl,tableLeft,tableTop)
// if (!this.selectionBordersVisibility) {
// return false;
// }
const {
left: cellLeft,
top: cellTop,
height: cellHeight,
width: cellWidth
} = cellEl.getBoundingClientRect()
// // console.log(605,cellEl.getBoundingClientRect(),this)
if (cellHeight && cellWidth) {
return {
left: cellLeft - tableLeft,
top: cellTop - tableTop,
width: cellWidth,
height: cellHeight
}
}
},
// get table el
getTableCellEl ({ rowKey, colKey }) {
let result = null
// const { tableEl } = this;
const tableEl = this.$refs[this.tableContentWrapperRef].$refs.table
// // console.log(566,tableEl)
if (tableEl) {
result = tableEl.querySelector(
`tbody tr[rowid="${rowKey}"] td[colid="${colKey}"]`
)
}
return result
},
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
})
// // console.log(727,result.selectionCurrent)
return result
},
getSelectionAutofillArea ({ areaPostions, fixedType }) {
let result = null
// // console.log(903)
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
}
// end cell above
else if (autoFillEndCellRect.top < areaPostions.topBorder.top) {
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
}
// auto fill end cell right
else if (
rightmostColKey === autoFillEndCell.colKey &&
!isEmptyValue(rightmostColKey)
) {
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
}
// auto fill end cell left
else if (
leftmostColKey === autoFillEndCell.colKey &&
!isEmptyValue(leftmostColKey)
) {
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.$emit(EMIT_EVENTS.AUTOFILLING_DIRECTION_CHANGE, autofillingDirection)
// this.dispatch(
// COMPS_NAME.VE_TABLE,
// EMIT_EVENTS.AUTOFILLING_DIRECTION_CHANGE,
// autofillingDirection,
// );
}
// // console.log(1095,result)
return result
},
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
}
},
getBorders ({
borderWidth,
borderHeight,
topBorder,
rightBorder,
bottomBorder,
leftBorder,
corner,
className,
fixedType,
totalColKeys,
fixedColKeys
}) {
const {
cornerCellInfo,
colgroups,
isFirstSelectionRow,
isFirstSelectionCol,
isFirstNotFixedSelectionCol,
showCorner
} = this
const scrollYStore = this.scrollYStore
const startIndex = scrollYStore.startIndex
const rowHeight = scrollYStore.rowHeight
const topSpaceHeight = Math.max(0, startIndex * rowHeight)
let isRender = true
if (fixedType) {
isRender = isExistGivenFixedColKey({
fixedType,
colKeys: totalColKeys,
colgroups
})
}
// middle normal area
else {
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
}
}
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: topSpaceHeight ? cornerTop + topSpaceHeight + 'px' : cornerTop + 'px',
left: cornerLeft + 'px',
borderWidth: `1px ${cornerBorderRightWidth} ${cornerBorderBottomtWidth} 1px`
},
on: {
mousedown: (e) => {
this.$emit(EMIT_EVENTS.SELECTION_CORNER_MOUSEDOWN, { event: e })
// this.dispatch(
// 'VxeSelecteAreaDom',
// EMIT_EVENTS.SELECTION_CORNER_MOUSEDOWN,
// {
// event: e,
// },
// );
},
mouseup: (e) => {
this.$emit(EMIT_EVENTS.SELECTION_CORNER_MOUSEUP, { event: e })
// this.dispatch(
// 'VxeSelecteAreaDom',
// EMIT_EVENTS.SELECTION_CORNER_MOUSEUP,
// {
// event: e,
// },
// );
}
}
}
// // console.log(1169,topBorder,corner)
return h('div', {
class: clsName(className)
}, [h('div', {
class: clsName('selection-border'),
style: {
display: topBorder.show ? 'block' : 'none',
width: borderWidth + 'px',
height: topBorder.height + 'px',
top: topSpaceHeight ? topBorder.top + topSpaceHeight + 'px' : topBorder.top + 'px',
left: topBorder.left + 'px'
}
}), h('div', {
class: clsName('selection-border'),
style: {
display: rightBorder.show ? 'block' : 'none',
width: rightBorder.width + 'px',
height: borderHeight + 'px',
top: topSpaceHeight ? rightBorder.top + topSpaceHeight + 'px' : rightBorder.top + 'px',
left: rightBorder.left + 'px'
}
}), h('div', {
class: clsName('selection-border'),
style: {
display: bottomBorder.show ? 'block' : 'none',
width: borderWidth + 'px',
height: bottomBorder.height + 'px',
top: topSpaceHeight ? bottomBorder.top + topSpaceHeight + 'px' : bottomBorder.top + 'px',
left: bottomBorder.left + 'px'
}
}), h('div', {
class: clsName('selection-border'),
style: {
display: leftBorder.show ? 'block' : 'none',
width: leftBorder.width + 'px',
height: borderHeight + 'px',
top: topSpaceHeight ? leftBorder.top + topSpaceHeight + 'px' : leftBorder.top + 'px',
left: leftBorder.left + 'px'
}
}), h('div', {
...cornerProps
})])
},
getSelectionAreas ({ fixedType }) {
// // console.log('1234选中区域',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) {
// // console.log(1248,cellSelectionRect)
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
}
// end cell column key left or equal
else if (leftmostColKey === normalEndCell.colKey) {
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
}
// end cell above or equal
else if (normalEndCellRect.top <= currentCellRect.top) {
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
})
// // console.log(14699999,totalColKeys,leftColKey,rightColKey)
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
})
// console.log(1665,result)
return result
},
getAreaLayer ({
borderWidth,
borderHeight,
topBorder,
className,
fixedType,
totalColKeys,
fixedColKeys
}) {
const { colgroups } = this
const scrollYStore = this.scrollYStore
const startIndex = scrollYStore.startIndex
const rowHeight = scrollYStore.rowHeight
const topSpaceHeight = Math.max(0, startIndex * rowHeight)
let isRender = true
if (fixedType) {
isRender = isExistGivenFixedColKey({
fixedType,
colKeys: totalColKeys,
colgroups
})
}
// middle normal area
else {
isRender = isExistNotFixedColKey({
colKeys: totalColKeys,
colgroups
})
}
// // console.log(152000000000000,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
}
}
// // console.log(1540)
return h('div', {
class: clsName(className),
style: {
top: topSpaceHeight ? topBorder.top + topSpaceHeight + 'px' : topBorder.top + 'px',
left: topBorder.left + 'px',
width: borderWidth + 'px',
height: borderHeight + 'px'
}
})
},
bodyCellMouseover ({ event, params }) {
const {
rowKeyFieldName,
isBodyCellMousedown,
isAutofillStarting,
isHeaderCellMousedown,
isBodyOperationColumnMousedown,
getRowid
} = this
// const rowKey = getRowKey(rowData, rowKeyFieldName);
const { row, column } = params
const rowKey = getRowid(row)
const colKey = column.id
if (isBodyCellMousedown) {
// 操作列不能单元格选中
if (isOperationColumn(colKey, this.colgroups)) {
return false
}
this.cellSelectionNormalEndCellChange({
rowKey,
colKey
})
}
if (isBodyOperationColumnMousedown) {
this.bodyIndicatorRowKeysChange({
startRowKey: this.bodyIndicatorRowKeys.startRowKey,
endRowKey: rowKey
})
}
// 允许在body cell mouseover 里补充 header indicator 信息
if (isHeaderCellMousedown) {
this.headerIndicatorColKeysChange({
startColKey: this.headerIndicatorColKeys.startColKey,
endColKey: colKey
})
}
if (isAutofillStarting) {
// 操作列不能autofilling 效果
if (isOperationColumn(colKey, this.colgroups)) {