UNPKG

vxe-table-select-area

Version:

一个基于 vxe-table 的可区域选中复制、粘贴的组件

295 lines (289 loc) 12.2 kB
import XEUtils from 'xe-utils' import UtilTools from '../../tools/utils' import DomTools from '../../tools/dom' import { convertToRows } from './util' import { getColReMinWidth } from '../../table/src/util' const cellType = 'header' export default { name: 'VxeTableHeader', props: { tableData: Array, tableColumn: Array, tableGroupColumn: Array, fixedColumn: Array, size: String, fixedType: String }, data () { return { headerColumn: [] } }, watch: { tableColumn () { this.uploadColumn() } }, created () { this.uploadColumn() }, mounted () { const { $parent: $xetable, $el, $refs, fixedType } = this const { elemStore } = $xetable const prefix = `${fixedType || 'main'}-header-` elemStore[`${prefix}wrapper`] = $el elemStore[`${prefix}table`] = $refs.table elemStore[`${prefix}colgroup`] = $refs.colgroup elemStore[`${prefix}list`] = $refs.thead elemStore[`${prefix}xSpace`] = $refs.xSpace elemStore[`${prefix}repair`] = $refs.repair }, destroyed () { const { $parent: $xetable, fixedType } = this const { elemStore } = $xetable const prefix = `${fixedType || 'main'}-header-` elemStore[`${prefix}wrapper`] = null elemStore[`${prefix}table`] = null elemStore[`${prefix}colgroup`] = null elemStore[`${prefix}list`] = null elemStore[`${prefix}xSpace`] = null elemStore[`${prefix}repair`] = null }, render (h) { const { _e, $parent: $xetable, fixedType, headerColumn, tableColumn, fixedColumn } = this const { $listeners: tableListeners, tId, isGroup, visibleColumn, resizable, border, columnKey, headerRowClassName, headerCellClassName, headerRowStyle, headerCellStyle, showHeaderOverflow: allColumnHeaderOverflow, headerAlign: allHeaderAlign, align: allAlign, highlightCurrentColumn, currentColumn, scrollXLoad, overflowX, scrollbarWidth, sortOpts, mouseConfig, columnOpts } = $xetable let headerGroups = headerColumn let renderColumnList = tableColumn if (isGroup) { renderColumnList = visibleColumn } else { // 如果是使用优化模式 if (fixedType) { if (scrollXLoad || allColumnHeaderOverflow) { renderColumnList = fixedColumn } } headerGroups = [renderColumnList] } return h('div', { class: ['vxe-table--header-wrapper', fixedType ? `fixed-${fixedType}--wrapper` : 'body--wrapper'], attrs: { xid: tId } }, [ fixedType ? _e() : h('div', { class: 'vxe-body--x-space', ref: 'xSpace' }), h('table', { class: 'vxe-table--header', attrs: { xid: tId, cellspacing: 0, cellpadding: 0, border: 0 }, ref: 'table' }, [ /** * 列宽 */ h('colgroup', { ref: 'colgroup' }, renderColumnList.map((column, $columnIndex) => { return h('col', { attrs: { name: column.id }, key: $columnIndex }) }).concat(scrollbarWidth ? [ h('col', { attrs: { name: 'col_gutter' } }) ] : [])), /** * 头部 */ h('thead', { ref: 'thead' }, headerGroups.map((cols, $rowIndex) => { return h('tr', { class: ['vxe-header--row', headerRowClassName ? XEUtils.isFunction(headerRowClassName) ? headerRowClassName({ $table: $xetable, $rowIndex, fixed: fixedType, type: cellType }) : headerRowClassName : ''], style: headerRowStyle ? (XEUtils.isFunction(headerRowStyle) ? headerRowStyle({ $table: $xetable, $rowIndex, fixed: fixedType, type: cellType }) : headerRowStyle) : null }, cols.map((column, $columnIndex) => { const { type, showHeaderOverflow, headerAlign, align, headerClassName } = column // const { enabled } = tooltipOpts const isColGroup = column.children && column.children.length const fixedHiddenColumn = fixedType ? column.fixed !== fixedType && !isColGroup : column.fixed && overflowX const headOverflow = XEUtils.isUndefined(showHeaderOverflow) || XEUtils.isNull(showHeaderOverflow) ? allColumnHeaderOverflow : showHeaderOverflow const headAlign = headerAlign || align || allHeaderAlign || allAlign let showEllipsis = headOverflow === 'ellipsis' const showTitle = headOverflow === 'title' const showTooltip = headOverflow === true || headOverflow === 'tooltip' let hasEllipsis = showTitle || showTooltip || showEllipsis const thOns = {} const hasFilter = column.filters && column.filters.some(item => item.checked) const columnIndex = $xetable.getColumnIndex(column) const _columnIndex = $xetable.getVTColumnIndex(column) const params = { $table: $xetable, $grid: $xetable.xegrid, $rowIndex, column, columnIndex, $columnIndex, _columnIndex, fixed: fixedType, type: cellType, isHidden: fixedHiddenColumn, hasFilter } // 虚拟滚动不支持动态高度 if (scrollXLoad && !hasEllipsis) { showEllipsis = hasEllipsis = true } if (columnOpts.isCurrent || highlightCurrentColumn || tableListeners['header-cell-click'] || sortOpts.trigger === 'cell') { thOns.click = evnt => $xetable.triggerHeaderCellClickEvent(evnt, params) } if (tableListeners['header-cell-dblclick']) { thOns.dblclick = evnt => $xetable.triggerHeaderCellDblclickEvent(evnt, params) } // 按下事件处理 if (mouseConfig) { thOns.mousedown = evnt => $xetable.triggerHeaderCellMousedownEvent(evnt, params) } return h('th', { class: ['vxe-header--column', column.id, { [`col--${headAlign}`]: headAlign, [`col--${type}`]: type, 'col--last': $columnIndex === cols.length - 1, 'col--fixed': column.fixed, 'col--group': isColGroup, 'col--ellipsis': hasEllipsis, 'fixed--hidden': fixedHiddenColumn, 'is--sortable': column.sortable, 'col--filter': !!column.filters, 'is--filter-active': hasFilter, 'col--current': currentColumn === column }, UtilTools.getClass(headerClassName, params), UtilTools.getClass(headerCellClassName, params)], attrs: { colid: column.id, colspan: column.colSpan > 1 ? column.colSpan : null, rowspan: column.rowSpan > 1 ? column.rowSpan : null }, style: headerCellStyle ? (XEUtils.isFunction(headerCellStyle) ? headerCellStyle(params) : headerCellStyle) : null, on: thOns, key: columnKey || columnOpts.useKey || isColGroup ? column.id : $columnIndex }, [ h('div', { class: ['vxe-cell', { 'c--title': showTitle, 'c--tooltip': showTooltip, 'c--ellipsis': showEllipsis }] }, column.renderHeader(h, params)), /** * 列宽拖动 */ !fixedHiddenColumn && !isColGroup && (XEUtils.isBoolean(column.resizable) ? column.resizable : (columnOpts.resizable || resizable)) ? h('div', { class: ['vxe-resizable', { 'is--line': !border || border === 'none' }], on: { mousedown: evnt => this.resizeMousedown(evnt, params) } }) : null ]) }).concat(scrollbarWidth ? [ h('th', { class: 'vxe-header--gutter col--gutter' }) ] : [])) })) ]), /** * 其他 */ h('div', { class: 'vxe-table--header-border-line', ref: 'repair' }) ]) }, methods: { uploadColumn () { const { $parent: $xetable } = this this.headerColumn = $xetable.isGroup ? convertToRows(this.tableGroupColumn) : [] }, resizeMousedown (evnt, params) { const { column } = params const { $parent: $xetable, $el, fixedType } = this const { tableBody, leftContainer, rightContainer, resizeBar: resizeBarElem } = $xetable.$refs const { target: dragBtnElem, clientX: dragClientX } = evnt const cell = params.cell = dragBtnElem.parentNode let dragLeft = 0 const tableBodyElem = tableBody.$el const pos = DomTools.getOffsetPos(dragBtnElem, $el) const dragBtnWidth = dragBtnElem.clientWidth const dragBtnOffsetWidth = Math.floor(dragBtnWidth / 2) const minInterval = getColReMinWidth(params) - dragBtnOffsetWidth // 列之间的最小间距 let dragMinLeft = pos.left - cell.clientWidth + dragBtnWidth + minInterval let dragPosLeft = pos.left + dragBtnOffsetWidth const domMousemove = document.onmousemove const domMouseup = document.onmouseup const isLeftFixed = fixedType === 'left' const isRightFixed = fixedType === 'right' // 计算左右侧固定列偏移量 let fixedOffsetWidth = 0 if (isLeftFixed || isRightFixed) { const siblingProp = isLeftFixed ? 'nextElementSibling' : 'previousElementSibling' let tempCellElem = cell[siblingProp] while (tempCellElem) { if (DomTools.hasClass(tempCellElem, 'fixed--hidden')) { break } else if (!DomTools.hasClass(tempCellElem, 'col--group')) { fixedOffsetWidth += tempCellElem.offsetWidth } tempCellElem = tempCellElem[siblingProp] } if (isRightFixed && rightContainer) { dragPosLeft = rightContainer.offsetLeft + fixedOffsetWidth } } // 处理拖动事件 const updateEvent = function (evnt) { evnt.stopPropagation() evnt.preventDefault() const offsetX = evnt.clientX - dragClientX let left = dragPosLeft + offsetX const scrollLeft = fixedType ? 0 : tableBodyElem.scrollLeft if (isLeftFixed) { // 左固定列(不允许超过右侧固定列、不允许超过右边距) left = Math.min(left, (rightContainer ? rightContainer.offsetLeft : tableBodyElem.clientWidth) - fixedOffsetWidth - minInterval) } else if (isRightFixed) { // 右侧固定列(不允许超过左侧固定列、不允许超过左边距) dragMinLeft = (leftContainer ? leftContainer.clientWidth : 0) + fixedOffsetWidth + minInterval left = Math.min(left, dragPosLeft + cell.clientWidth - minInterval) } else { dragMinLeft = Math.max(tableBodyElem.scrollLeft, dragMinLeft) // left = Math.min(left, tableBodyElem.clientWidth + tableBodyElem.scrollLeft - 40) } dragLeft = Math.max(left, dragMinLeft) resizeBarElem.style.left = `${dragLeft - scrollLeft}px` } $xetable._isResize = true DomTools.addClass($xetable.$el, 'drag--resize') resizeBarElem.style.display = 'block' document.onmousemove = updateEvent document.onmouseup = function (evnt) { document.onmousemove = domMousemove document.onmouseup = domMouseup const resizeWidth = column.renderWidth + (isRightFixed ? dragPosLeft - dragLeft : dragLeft - dragPosLeft) column.resizeWidth = resizeWidth resizeBarElem.style.display = 'none' $xetable._isResize = false $xetable._lastResizeTime = Date.now() $xetable.analyColumnWidth() $xetable.recalculate(true).then(() => { $xetable.saveCustomResizable() $xetable.updateCellAreas() $xetable.emitEvent('resizable-change', { ...params, resizeWidth }, evnt) }) DomTools.removeClass($xetable.$el, 'drag--resize') } updateEvent(evnt) $xetable.closeMenu() } } }