vxe-table-select-area
Version:
一个基于 vxe-table 的可区域选中复制、粘贴的组件
283 lines (259 loc) • 9.78 kB
JavaScript
import VXETable from '../../v-x-e-table'
import XEUtils from 'xe-utils'
import { ColumnInfo } from './columnInfo'
import DomTools from '../../tools/dom'
const lineOffsetSizes = {
mini: 3,
small: 2,
medium: 1
}
export function restoreScrollLocation (_vm, scrollLeft, scrollTop) {
return _vm.clearScroll().then(() => {
if (scrollLeft || scrollTop) {
// 重置最后滚动状态
_vm.lastScrollLeft = 0
_vm.lastScrollTop = 0
// 还原滚动状态
return _vm.scrollTo(scrollLeft, scrollTop)
}
})
}
export function toTreePathSeq (path) {
return path.map((num, i) => i % 2 === 0 ? (Number(num) + 1) : '.').join('')
}
export function removeScrollListener (scrollElem) {
if (scrollElem && scrollElem._onscroll) {
scrollElem.onscroll = null
}
}
export function restoreScrollListener (scrollElem) {
if (scrollElem && scrollElem._onscroll) {
scrollElem.onscroll = scrollElem._onscroll
}
}
// 行主键 key
export function getRowkey ($xetable) {
return $xetable.rowOpts.keyField || $xetable.rowId || '_X_ROW_KEY'
}
// 行主键 value
export function getRowid ($xetable, row) {
const rowid = XEUtils.get(row, getRowkey($xetable))
return XEUtils.eqNull(rowid) ? '' : encodeURIComponent(rowid)
}
function getPaddingLeftRightSize (elem) {
if (elem) {
const computedStyle = getComputedStyle(elem)
const paddingLeft = XEUtils.toNumber(computedStyle.paddingLeft)
const paddingRight = XEUtils.toNumber(computedStyle.paddingRight)
return paddingLeft + paddingRight
}
return 0
}
function getElemenMarginWidth (elem) {
if (elem) {
const computedStyle = getComputedStyle(elem)
const marginLeft = XEUtils.toNumber(computedStyle.marginLeft)
const marginRight = XEUtils.toNumber(computedStyle.marginRight)
return elem.offsetWidth + marginLeft + marginRight
}
return 0
}
export function handleFieldOrColumn (_vm, fieldOrColumn) {
if (fieldOrColumn) {
return XEUtils.isString(fieldOrColumn) ? _vm.getColumnByField(fieldOrColumn) : fieldOrColumn
}
return null
}
function queryCellElement (cell, selector) {
return cell.querySelector('.vxe-cell' + selector)
}
export function toFilters (filters) {
if (filters && XEUtils.isArray(filters)) {
return filters.map(({ label, value, data, resetValue, checked }) => {
return { label, value, data, resetValue, checked: !!checked, _checked: !!checked }
})
}
return filters
}
export function getColReMinWidth (params) {
const { $table, column, cell } = params
const { showHeaderOverflow: allColumnHeaderOverflow, resizableOpts } = $table
const { minWidth } = resizableOpts
// 如果自定义调整宽度逻辑
if (minWidth) {
const customMinWidth = XEUtils.isFunction(minWidth) ? minWidth(params) : minWidth
if (customMinWidth !== 'auto') {
return Math.max(1, XEUtils.toNumber(customMinWidth))
}
}
const { showHeaderOverflow, minWidth: colMinWidth } = column
const headOverflow = XEUtils.isUndefined(showHeaderOverflow) || XEUtils.isNull(showHeaderOverflow) ? allColumnHeaderOverflow : showHeaderOverflow
const showEllipsis = headOverflow === 'ellipsis'
const showTitle = headOverflow === 'title'
const showTooltip = headOverflow === true || headOverflow === 'tooltip'
const hasEllipsis = showTitle || showTooltip || showEllipsis
const minTitleWidth = XEUtils.floor((XEUtils.toNumber(getComputedStyle(cell).fontSize) || 14) * 1.6)
const paddingLeftRight = getPaddingLeftRightSize(cell) + getPaddingLeftRightSize(queryCellElement(cell, ''))
let mWidth = minTitleWidth + paddingLeftRight
// 默认最小宽处理
if (hasEllipsis) {
const checkboxIconWidth = getPaddingLeftRightSize(queryCellElement(cell, '--title>.vxe-cell--checkbox'))
const requiredIconWidth = getElemenMarginWidth(queryCellElement(cell, '>.vxe-cell--required-icon'))
const editIconWidth = getElemenMarginWidth(queryCellElement(cell, '>.vxe-cell--edit-icon'))
const helpIconWidth = getElemenMarginWidth(queryCellElement(cell, '>.vxe-cell-help-icon'))
const sortIconWidth = getElemenMarginWidth(queryCellElement(cell, '>.vxe-cell--sort'))
const filterIconWidth = getElemenMarginWidth(queryCellElement(cell, '>.vxe-cell--filter'))
mWidth += checkboxIconWidth + requiredIconWidth + editIconWidth + helpIconWidth + filterIconWidth + sortIconWidth
}
// 如果设置最小宽
if (colMinWidth) {
const { tableBody } = $table.$refs
const bodyElem = tableBody ? tableBody.$el : null
if (bodyElem) {
if (DomTools.isScale(colMinWidth)) {
const bodyWidth = bodyElem.clientWidth - 1
const meanWidth = bodyWidth / 100
return Math.max(mWidth, Math.floor(XEUtils.toInteger(colMinWidth) * meanWidth))
} else if (DomTools.isPx(colMinWidth)) {
return Math.max(mWidth, XEUtils.toInteger(colMinWidth))
}
}
}
return mWidth
}
function countTreeExpand (prevRow, params) {
let count = 1
if (!prevRow) {
return count
}
const { $table } = params
const rowChildren = prevRow[$table.treeOpts.children]
if ($table.isTreeExpandByRow(prevRow)) {
for (let index = 0; index < rowChildren.length; index++) {
count += countTreeExpand(rowChildren[index], params)
}
}
return count
}
export function getOffsetSize ($xetable) {
return lineOffsetSizes[$xetable.vSize] || 0
}
export function calcTreeLine (params, items, rIndex) {
const { $table } = params
let expandSize = 1
if (rIndex) {
expandSize = countTreeExpand(items[rIndex - 1], params)
}
return $table.rowHeight * expandSize - (rIndex ? 1 : (12 - getOffsetSize($table)))
}
export function mergeBodyMethod (mergeList, _rowIndex, _columnIndex) {
for (let mIndex = 0; mIndex < mergeList.length; mIndex++) {
const { row: mergeRowIndex, col: mergeColIndex, rowspan: mergeRowspan, colspan: mergeColspan } = mergeList[mIndex]
if (mergeColIndex > -1 && mergeRowIndex > -1 && mergeRowspan && mergeColspan) {
if (mergeRowIndex === _rowIndex && mergeColIndex === _columnIndex) {
return { rowspan: mergeRowspan, colspan: mergeColspan }
}
if (_rowIndex >= mergeRowIndex && _rowIndex < mergeRowIndex + mergeRowspan && _columnIndex >= mergeColIndex && _columnIndex < mergeColIndex + mergeColspan) {
return { rowspan: 0, colspan: 0 }
}
}
}
}
export function clearTableDefaultStatus (_vm) {
_vm.initStatus = false
_vm.clearSort()
_vm.clearCurrentRow()
_vm.clearCurrentColumn()
_vm.clearRadioRow()
_vm.clearRadioReserve()
_vm.clearCheckboxRow()
_vm.clearCheckboxReserve()
_vm.clearRowExpand()
_vm.clearTreeExpand()
_vm.clearTreeExpandReserve()
if (_vm.clearActived && VXETable._edit) {
_vm.clearActived()
}
if (_vm.clearSelected && (_vm.keyboardConfig || _vm.mouseConfig)) {
_vm.clearSelected()
}
if (_vm.clearCellAreas && _vm.mouseConfig) {
_vm.clearCellAreas()
_vm.clearCopyCellArea()
}
return _vm.clearScroll()
}
export function clearTableAllStatus (_vm) {
if (_vm.clearFilter && VXETable._filter) {
_vm.clearFilter()
}
return clearTableDefaultStatus(_vm)
}
export function isColumnInfo (column) {
return column instanceof ColumnInfo
}
export function getColumnConfig ($xetable, _vm, options) {
return isColumnInfo(_vm) ? _vm : new ColumnInfo($xetable, _vm, options)
}
export function rowToVisible ($xetable, row) {
const { tableBody } = $xetable.$refs
const bodyElem = tableBody ? tableBody.$el : null
if (bodyElem) {
const trElem = bodyElem.querySelector(`[rowid="${getRowid($xetable, row)}"]`)
if (trElem) {
const bodyHeight = bodyElem.clientHeight
const bodySrcollTop = bodyElem.scrollTop
const trOffsetTop = trElem.offsetTop + (trElem.offsetParent ? trElem.offsetParent.offsetTop : 0)
const trHeight = trElem.clientHeight
// 检测行是否在可视区中
if (trOffsetTop < bodySrcollTop || trOffsetTop > bodySrcollTop + bodyHeight) {
// 向上定位
return $xetable.scrollTo(null, trOffsetTop)
} else if (trOffsetTop + trHeight >= bodyHeight + bodySrcollTop) {
// 向下定位
return $xetable.scrollTo(null, bodySrcollTop + trHeight)
}
} else {
// 如果是虚拟渲染跨行滚动
if ($xetable.scrollYLoad) {
return $xetable.scrollTo(null, ($xetable.afterFullData.indexOf(row) - 1) * $xetable.scrollYStore.rowHeight)
}
}
}
return Promise.resolve()
}
export function colToVisible ($xetable, column) {
const { tableBody } = $xetable.$refs
const bodyElem = tableBody ? tableBody.$el : null
if (bodyElem) {
const tdElem = bodyElem.querySelector(`.${column.id}`)
if (tdElem) {
const bodyWidth = bodyElem.clientWidth
const bodySrcollLeft = bodyElem.scrollLeft
const tdOffsetLeft = tdElem.offsetLeft + (tdElem.offsetParent ? tdElem.offsetParent.offsetLeft : 0)
const tdWidth = tdElem.clientWidth
// 检测行是否在可视区中
if (tdOffsetLeft < bodySrcollLeft || tdOffsetLeft > bodySrcollLeft + bodyWidth) {
// 向左定位
return $xetable.scrollTo(tdOffsetLeft)
} else if (tdOffsetLeft + tdWidth >= bodyWidth + bodySrcollLeft) {
// 向右定位
return $xetable.scrollTo(bodySrcollLeft + tdWidth)
}
} else {
// 如果是虚拟渲染跨行滚动
if ($xetable.scrollXLoad) {
const visibleColumn = $xetable.visibleColumn
let scrollLeft = 0
for (let index = 0; index < visibleColumn.length; index++) {
if (visibleColumn[index] === column) {
break
}
scrollLeft += visibleColumn[index].renderWidth
}
return $xetable.scrollTo(scrollLeft)
}
}
}
return Promise.resolve()
}