| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504 |
- import XEUtils from 'xe-utils'
- import { getRefElem } from '../../src/util'
- import { getAbsolutePos, addClass, removeClass, hasControlKey } from '../../../ui/src/dom'
- import type { VxeTableConstructor, VxeTablePrivateMethods, VxeTableDefines, TableReactData, TableInternalData } from '../../../../types'
- function getCheckboxRangeRows ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, evnt: MouseEvent, params: any, targetTrElem: HTMLElement, trRect: DOMRect, offsetClientTop: number, moveRange: number) {
- const props = $xeTable
- const reactData = $xeTable as unknown as TableReactData
- const internalData = $xeTable as unknown as TableInternalData
- const { showOverflow } = props
- const { fullAllDataRowIdData, isResizeCellHeight } = internalData
- const rowOpts = $xeTable.computeRowOpts
- const cellOpts = $xeTable.computeCellOpts
- const defaultRowHeight = $xeTable.computeDefaultRowHeight
- const { row } = params
- let countHeight = 0
- let rangeRows: any[] = []
- let moveSize = 0
- const isDown = moveRange > 0
- const { scrollYLoad } = reactData
- const { afterFullData } = internalData
- if (isDown) {
- moveSize = offsetClientTop + moveRange
- } else {
- moveSize = (trRect.height - offsetClientTop) + Math.abs(moveRange)
- }
- if (scrollYLoad) {
- const _rowIndex = $xeTable.getVTRowIndex(row)
- const isCustomCellHeight = isResizeCellHeight || cellOpts.height || rowOpts.height
- if (!isCustomCellHeight && showOverflow) {
- if (isDown) {
- rangeRows = afterFullData.slice(_rowIndex, _rowIndex + Math.ceil(moveSize / defaultRowHeight))
- } else {
- rangeRows = afterFullData.slice(_rowIndex - Math.floor(moveSize / defaultRowHeight), _rowIndex + 1)
- }
- } else {
- if (isDown) {
- for (let i = _rowIndex; i < afterFullData.length; i++) {
- const item = afterFullData[i]
- const rowid = $xeTable.getRowid(item)
- const rowRest = fullAllDataRowIdData[rowid] || {}
- countHeight += rowRest.resizeHeight || cellOpts.height || rowOpts.height || rowRest.height || defaultRowHeight
- rangeRows.push(item)
- if (countHeight > moveSize) {
- return rangeRows
- }
- }
- } else {
- for (let len = _rowIndex; len >= 0; len--) {
- const item = afterFullData[len]
- const rowid = $xeTable.getRowid(item)
- const rowRest = fullAllDataRowIdData[rowid] || {}
- countHeight += rowRest.resizeHeight || cellOpts.height || rowOpts.height || rowRest.height || defaultRowHeight
- rangeRows.push(item)
- if (countHeight > moveSize) {
- return rangeRows
- }
- }
- }
- }
- } else {
- const siblingProp = isDown ? 'next' : 'previous'
- while (targetTrElem && countHeight < moveSize) {
- const rowNodeRest = $xeTable.getRowNode(targetTrElem)
- if (rowNodeRest) {
- rangeRows.push(rowNodeRest.item)
- countHeight += targetTrElem.offsetHeight
- targetTrElem = targetTrElem[`${siblingProp}ElementSibling`] as HTMLElement
- }
- }
- }
- return rangeRows
- }
- function handleMoveSelected ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, evnt: any, args: any, isLeftArrow: boolean, isUpArrow: boolean, isRightArrow: boolean, isDwArrow: boolean) {
- const internalData = $xeTable as unknown as TableInternalData
- const { afterFullData, visibleColumn } = internalData
- const params = Object.assign({}, args)
- const _rowIndex = $xeTable.getVTRowIndex(params.row)
- const _columnIndex = $xeTable.getVTColumnIndex(params.column)
- evnt.preventDefault()
- if (isUpArrow && _rowIndex > 0) {
- // 移动到上一行
- params.rowIndex = _rowIndex - 1
- params.row = afterFullData[params.rowIndex]
- } else if (isDwArrow && _rowIndex < afterFullData.length - 1) {
- // 移动到下一行
- params.rowIndex = _rowIndex + 1
- params.row = afterFullData[params.rowIndex]
- } else if (isLeftArrow && _columnIndex) {
- // 移动到左侧单元格
- params.columnIndex = _columnIndex - 1
- params.column = visibleColumn[params.columnIndex]
- } else if (isRightArrow && _columnIndex < visibleColumn.length - 1) {
- // 移动到右侧单元格
- params.columnIndex = _columnIndex + 1
- params.column = visibleColumn[params.columnIndex]
- }
- $xeTable.scrollToRow(params.row, params.column).then(() => {
- params.cell = $xeTable.getCellElement(params.row, params.column)
- $xeTable.handleSelected(params, evnt)
- })
- return params
- }
- function handleCheckboxRangeEvent ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, evnt: any, params: any) {
- const internalData = $xeTable as unknown as TableInternalData
- const { elemStore } = internalData
- const bodyScrollElem = getRefElem(elemStore['main-body-scroll'])
- const leftScrollElem = getRefElem(elemStore['left-body-scroll'])
- const rightScrollElem = getRefElem(elemStore['right-body-scroll'])
- const { column, cell } = params
- if (column.type === 'checkbox') {
- let bodyWrapperElem = bodyScrollElem as HTMLElement
- if (leftScrollElem && column.fixed === 'left') {
- bodyWrapperElem = leftScrollElem
- } else if (rightScrollElem && column.fixed === 'right') {
- bodyWrapperElem = rightScrollElem
- }
- if (!bodyWrapperElem) {
- return
- }
- const bodyRect = bodyWrapperElem.getBoundingClientRect()
- const el = $xeTable.$refs.refElem as HTMLDivElement
- const disX = evnt.clientX
- const disY = evnt.clientY
- const checkboxRangeElem = bodyWrapperElem.querySelector('.vxe-table--checkbox-range') as HTMLElement
- const trElem = cell.parentNode
- const selectRecords = $xeTable.getCheckboxRecords()
- let lastRangeRows = []
- const marginSize = 1
- const startTop = evnt.clientY - bodyRect.y + bodyWrapperElem.scrollTop
- const startLeft = evnt.clientX - bodyRect.x + bodyWrapperElem.scrollLeft
- const startScrollTop = bodyWrapperElem.scrollTop
- const rowHeight = trElem.offsetHeight
- const trRect = trElem.getBoundingClientRect()
- const offsetClientTop = disY - trRect.y
- let mouseScrollTimeout: any = null
- let isMouseScrollDown: any = false
- let mouseScrollSpaceSize = 1
- const triggerEvent = (type: 'change' | 'start' | 'end', evnt: Event) => {
- $xeTable.dispatchEvent(`checkbox-range-${type}`, {
- records: () => $xeTable.getCheckboxRecords(),
- reserves: () => $xeTable.getCheckboxReserveRecords()
- }, evnt)
- }
- const handleChecked = (evnt: any) => {
- const { clientX, clientY } = evnt
- const offsetLeft = clientX - disX
- const offsetTop = clientY - disY + (bodyWrapperElem.scrollTop - startScrollTop)
- let rangeHeight = Math.abs(offsetTop)
- let rangeWidth = Math.abs(offsetLeft)
- let rangeTop = startTop
- let rangeLeft = startLeft
- if (offsetTop < marginSize) {
- // 向上
- rangeTop += offsetTop
- if (rangeTop < marginSize) {
- rangeTop = marginSize
- rangeHeight = startTop
- }
- } else {
- // 向下
- rangeHeight = Math.min(rangeHeight, bodyWrapperElem.scrollHeight - startTop - marginSize)
- }
- if (offsetLeft < marginSize) {
- // 向左
- rangeLeft += offsetLeft
- if (rangeWidth > startLeft) {
- rangeLeft = marginSize
- rangeWidth = startLeft
- }
- } else {
- // 向右
- rangeWidth = Math.min(rangeWidth, bodyWrapperElem.clientWidth - startLeft - marginSize)
- }
- checkboxRangeElem.style.height = `${rangeHeight}px`
- checkboxRangeElem.style.width = `${rangeWidth}px`
- checkboxRangeElem.style.left = `${rangeLeft}px`
- checkboxRangeElem.style.top = `${rangeTop}px`
- checkboxRangeElem.style.display = 'block'
- const rangeRows = getCheckboxRangeRows($xeTable, evnt, params, trElem, trRect, offsetClientTop, offsetTop < marginSize ? -rangeHeight : rangeHeight)
- // 至少滑动 10px 才能有效匹配
- if (rangeHeight > 10 && rangeRows.length !== lastRangeRows.length) {
- const isControlKey = hasControlKey(evnt)
- lastRangeRows = rangeRows
- if (isControlKey) {
- rangeRows.forEach((row: any) => {
- $xeTable.handleBatchSelectRows([row], selectRecords.indexOf(row) === -1)
- })
- } else {
- $xeTable.setAllCheckboxRow(false)
- $xeTable.handleCheckedCheckboxRow(rangeRows, true, false)
- }
- triggerEvent('change', evnt)
- }
- }
- // 停止鼠标滚动
- const stopMouseScroll = () => {
- clearTimeout(mouseScrollTimeout)
- mouseScrollTimeout = null
- }
- // 开始鼠标滚动
- const startMouseScroll = (evnt: any) => {
- stopMouseScroll()
- mouseScrollTimeout = setTimeout(() => {
- if (mouseScrollTimeout) {
- const { scrollLeft, scrollTop, clientHeight, scrollHeight } = bodyWrapperElem
- const topSize = Math.ceil(mouseScrollSpaceSize * 50 / rowHeight)
- if (isMouseScrollDown) {
- if (scrollTop + clientHeight < scrollHeight) {
- $xeTable.scrollTo(scrollLeft, scrollTop + topSize)
- startMouseScroll(evnt)
- handleChecked(evnt)
- } else {
- stopMouseScroll()
- }
- } else {
- if (scrollTop) {
- $xeTable.scrollTo(scrollLeft, scrollTop - topSize)
- startMouseScroll(evnt)
- handleChecked(evnt)
- } else {
- stopMouseScroll()
- }
- }
- }
- }, 50)
- }
- addClass(el, 'drag--range')
- document.onmousemove = evnt => {
- evnt.preventDefault()
- evnt.stopPropagation()
- const { clientY } = evnt
- const { boundingTop } = getAbsolutePos(bodyWrapperElem)
- // 如果超过可视区,触发滚动
- if (clientY < boundingTop) {
- isMouseScrollDown = false
- mouseScrollSpaceSize = boundingTop - clientY
- if (!mouseScrollTimeout) {
- startMouseScroll(evnt)
- }
- } else if (clientY > boundingTop + bodyWrapperElem.clientHeight) {
- isMouseScrollDown = true
- mouseScrollSpaceSize = clientY - boundingTop - bodyWrapperElem.clientHeight
- if (!mouseScrollTimeout) {
- startMouseScroll(evnt)
- }
- } else if (mouseScrollTimeout) {
- stopMouseScroll()
- }
- handleChecked(evnt)
- }
- document.onmouseup = (evnt) => {
- stopMouseScroll()
- removeClass(el, 'drag--range')
- checkboxRangeElem.removeAttribute('style')
- document.onmousemove = null
- document.onmouseup = null
- triggerEvent('end', evnt)
- }
- triggerEvent('start', evnt)
- }
- }
- export default {
- methods: {
- // 处理 Tab 键移动
- moveTabSelected (args: any, isLeft: any, evnt: any) {
- const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
- const props = $xeTable
- const internalData = $xeTable as unknown as TableInternalData
- const { editConfig } = props
- const { afterFullData, visibleColumn } = internalData
- const editOpts = $xeTable.computeEditOpts
- const rowOpts = $xeTable.computeRowOpts
- const currentRowOpts = $xeTable.computeCurrentRowOpts
- const columnOpts = $xeTable.computeColumnOpts
- const currentColumnOpts = $xeTable.computeCurrentColumnOpts
- let targetRow: any
- let targetRowIndex: any
- let targetColumnIndex: any
- const params = Object.assign({}, args)
- const _rowIndex = $xeTable.getVTRowIndex(params.row)
- const _columnIndex = $xeTable.getVTColumnIndex(params.column)
- evnt.preventDefault()
- if (isLeft) {
- // 向左
- if (_columnIndex <= 0) {
- // 如果已经是第一列,则移动到上一行
- if (_rowIndex > 0) {
- targetRowIndex = _rowIndex - 1
- targetRow = afterFullData[targetRowIndex]
- targetColumnIndex = visibleColumn.length - 1
- }
- } else {
- targetColumnIndex = _columnIndex - 1
- }
- } else {
- if (_columnIndex >= visibleColumn.length - 1) {
- // 如果已经是第一列,则移动到上一行
- if (_rowIndex < afterFullData.length - 1) {
- targetRowIndex = _rowIndex + 1
- targetRow = afterFullData[targetRowIndex]
- targetColumnIndex = 0
- }
- } else {
- targetColumnIndex = _columnIndex + 1
- }
- }
- const targetColumn = visibleColumn[targetColumnIndex]
- if (targetColumn) {
- if (targetRow) {
- params.rowIndex = targetRowIndex
- params.row = targetRow
- } else {
- params.rowIndex = _rowIndex
- }
- params.columnIndex = targetColumnIndex
- params.column = targetColumn
- params.cell = $xeTable.getCellElement(params.row, params.column)
- if (rowOpts.isCurrent && currentRowOpts.isFollowSelected) {
- $xeTable.triggerCurrentRowEvent(evnt, params)
- }
- if (columnOpts.isCurrent && currentColumnOpts.isFollowSelected) {
- $xeTable.triggerCurrentColumnEvent(evnt, params)
- }
- if (editConfig) {
- if (editOpts.trigger === 'click' || editOpts.trigger === 'dblclick') {
- if (editOpts.mode === 'row') {
- $xeTable.handleEdit(params, evnt)
- } else {
- $xeTable.scrollToRow(params.row, params.column)
- .then(() => {
- $xeTable.handleSelected(params, evnt)
- })
- }
- }
- } else {
- $xeTable.scrollToRow(params.row, params.column)
- .then(() => {
- $xeTable.handleSelected(params, evnt)
- })
- }
- }
- },
- // 处理当前行方向键移动
- moveCurrentRow (isUpArrow: boolean, isDwArrow: boolean, evnt: any) {
- const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
- const props = $xeTable
- const reactData = $xeTable as unknown as TableReactData
- const internalData = $xeTable as unknown as TableInternalData
- const { treeConfig } = props
- const { currentRow } = reactData
- const { afterFullData } = internalData
- const treeOpts = $xeTable.computeTreeOpts
- const childrenField = treeOpts.children || treeOpts.childrenField
- let targetRow
- if (currentRow) {
- if (treeConfig) {
- const { index, items } = XEUtils.findTree(afterFullData, item => item === currentRow, { children: childrenField })
- if (isUpArrow && index > 0) {
- targetRow = items[index - 1]
- } else if (isDwArrow && index < items.length - 1) {
- targetRow = items[index + 1]
- }
- } else {
- const _rowIndex = $xeTable.getVTRowIndex(currentRow)
- if (isUpArrow && _rowIndex > 0) {
- targetRow = afterFullData[_rowIndex - 1]
- } else if (isDwArrow && _rowIndex < afterFullData.length - 1) {
- targetRow = afterFullData[_rowIndex + 1]
- }
- }
- } else {
- targetRow = afterFullData[0]
- }
- if (targetRow) {
- evnt.preventDefault()
- const params = {
- $table: $xeTable,
- row: targetRow,
- rowIndex: $xeTable.getRowIndex(targetRow),
- $rowIndex: $xeTable.getVMRowIndex(targetRow)
- }
- $xeTable.scrollToRow(targetRow)
- .then(() => $xeTable.triggerCurrentRowEvent(evnt, params))
- }
- },
- // 处理当前列方向键移动
- moveCurrentColumn (isLeftArrow: boolean, isRightArrow: boolean, evnt: any) {
- const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
- const reactData = $xeTable as unknown as TableReactData
- const internalData = $xeTable as unknown as TableInternalData
- const { currentColumn } = reactData
- const { visibleColumn } = internalData
- let targetCol: VxeTableDefines.ColumnInfo | null = null
- if (currentColumn) {
- const _columnIndex = $xeTable.getVTColumnIndex(currentColumn)
- if (isLeftArrow && _columnIndex > 0) {
- targetCol = visibleColumn[_columnIndex - 1]
- } else if (isRightArrow && _columnIndex < visibleColumn.length - 1) {
- targetCol = visibleColumn[_columnIndex + 1]
- }
- } else {
- targetCol = visibleColumn[0]
- }
- if (targetCol) {
- evnt.preventDefault()
- const params = {
- $table: $xeTable,
- column: targetCol,
- columnIndex: $xeTable.getColumnIndex(targetCol),
- $columnIndex: $xeTable.getVMColumnIndex(targetCol)
- }
- $xeTable.scrollToColumn(targetCol)
- .then(() => $xeTable.triggerCurrentColumnEvent(evnt, params))
- }
- },
- // 处理可编辑方向键移动
- moveArrowSelected (args: any, isLeftArrow: boolean, isUpArrow: boolean, isRightArrow: boolean, isDwArrow: boolean, evnt: any) {
- const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
- const props = $xeTable
- const { highlightCurrentRow, highlightCurrentColumn } = props
- const rowOpts = $xeTable.computeRowOpts
- const currentRowOpts = $xeTable.computeCurrentRowOpts
- const columnOpts = $xeTable.computeColumnOpts
- const currentColumnOpts = $xeTable.computeCurrentColumnOpts
- const params = handleMoveSelected($xeTable, evnt, args, isLeftArrow, isUpArrow, isRightArrow, isDwArrow)
- if (rowOpts.isCurrent || highlightCurrentRow) {
- if (currentRowOpts.isFollowSelected) {
- $xeTable.triggerCurrentRowEvent(evnt, params)
- } else {
- // 当前行按键上下移动
- if ((isUpArrow || isDwArrow) && (rowOpts.isCurrent || highlightCurrentRow)) {
- $xeTable.moveCurrentRow(isUpArrow, isDwArrow, evnt)
- }
- }
- }
- if (columnOpts.isCurrent || highlightCurrentColumn) {
- if (currentColumnOpts.isFollowSelected) {
- $xeTable.triggerCurrentColumnEvent(evnt, params)
- } else {
- // 当前行按键左右移动
- if ((isLeftArrow || isRightArrow) && (columnOpts.isCurrent || highlightCurrentColumn)) {
- $xeTable.moveCurrentColumn(isLeftArrow, isRightArrow, evnt)
- }
- }
- }
- },
- moveEnterSelected (args: any, isLeftArrow: boolean, isUpArrow: boolean, isRightArrow: boolean, isDwArrow: boolean, evnt: any) {
- const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
- const props = $xeTable
- const { highlightCurrentRow, highlightCurrentColumn } = props
- const rowOpts = $xeTable.computeRowOpts
- const currentRowOpts = $xeTable.computeCurrentRowOpts
- const columnOpts = $xeTable.computeColumnOpts
- const currentColumnOpts = $xeTable.computeCurrentColumnOpts
- const params = handleMoveSelected($xeTable, evnt, args, isLeftArrow, isUpArrow, isRightArrow, isDwArrow)
- if (((rowOpts.isCurrent || highlightCurrentRow) && currentRowOpts.isFollowSelected)) {
- $xeTable.triggerCurrentRowEvent(evnt, params)
- }
- if ((columnOpts.isCurrent || highlightCurrentColumn) && currentColumnOpts.isFollowSelected) {
- $xeTable.triggerCurrentColumnEvent(evnt, params)
- }
- },
- // 处理可编辑方向键移动
- moveSelected (args: any, isLeftArrow: boolean, isUpArrow: boolean, isRightArrow: boolean, isDwArrow: boolean, evnt: any) {
- const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
- handleMoveSelected($xeTable, evnt, args, isLeftArrow, isUpArrow, isRightArrow, isDwArrow)
- },
- handleCellMousedownEvent (evnt: any, params: any) {
- const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
- const props = $xeTable
- const { editConfig, checkboxConfig, mouseConfig } = props
- const checkboxOpts = $xeTable.computeCheckboxOpts
- const mouseOpts = $xeTable.computeMouseOpts
- const editOpts = $xeTable.computeEditOpts
- if (mouseConfig && mouseOpts.area && $xeTable.triggerCellAreaModnEvent) {
- return $xeTable.triggerCellAreaModnEvent(evnt, params)
- } else {
- if (checkboxConfig && checkboxOpts.range) {
- handleCheckboxRangeEvent($xeTable, evnt, params)
- }
- if (mouseConfig && mouseOpts.selected) {
- if (!editConfig || editOpts.mode === 'cell') {
- $xeTable.handleSelected(params, evnt)
- }
- }
- }
- }
- }
- }
|