UNPKG

vue-fantable

Version:
317 lines (286 loc) 8.62 kB
import { clsName } from '../util/index' import { COMPS_NAME, HOOKS_NAME } from '../util/constant' import { isNumber } from '../../../src/utils/index.js' export default { name: COMPS_NAME.FAN_TABLE_COLUMN_RESISZER, props: { parentRendered: { type: Boolean, required: true, }, tableContainerEl: { type: HTMLDivElement, default: null, }, hooks: { type: Object, required: true, }, colgroups: { type: Array, required: true, }, isColumnResizerHover: { type: Boolean, required: true, }, isColumnResizing: { type: Boolean, required: true, }, setIsColumnResizerHover: { type: Function, required: true, }, setIsColumnResizing: { type: Function, required: true, }, setColumnWidth: { type: Function, required: true, }, // column width resize option columnWidthResizeOption: { type: Object, default: function () { return null }, }, }, data() { return { // column resizer start x columnResizerStartX: 0, // current resizing column currentResizingColumn: null, // column resizer handler width columnResizerHandlerWidth: 5, // column resizer rect columnResizerRect: { top: 0, left: 0, height: 0, }, } }, computed: { // column min width columnMinWidth() { let result = 30 const { columnWidthResizeOption } = this if (columnWidthResizeOption) { const { minWidth } = columnWidthResizeOption if (isNumber(minWidth) && minWidth > 0) { result = minWidth } } return result }, }, watch: { parentRendered: { handler: function (val) { if (val) { // header cell mousemove this.hooks.addHook( HOOKS_NAME.HEADER_CELL_MOUSEMOVE, ({ event, column }) => { if (column.disableResizing) return this.initColumnResizerPosition({ event, column }) }, ) } }, immediate: true, }, }, methods: { // init column resizer position initColumnResizerPosition({ event, column }) { const { tableContainerEl, isColumnResizing } = this if (tableContainerEl && !isColumnResizing) { const { left: tableContainerLeft, top: tableContainerTop } = tableContainerEl.getBoundingClientRect() const col = this.colgroups.find((x) => x.key === column.key) // 表头分组,不支持分组表头列宽拖动 if (!col) { return false } if (col._realTimeWidth) { const target = event.target const cellRect = target.getBoundingClientRect() const { height, left, top } = cellRect this.columnResizerRect.left = left + col._realTimeWidth - tableContainerLeft this.columnResizerRect.top = top - tableContainerTop this.columnResizerRect.height = height this.currentResizingColumn = col this.columnResizerStartX = left + col._realTimeWidth } else { console.warn('Resizer column needs set column width') } } }, // set column resizer position byu drag setColumnResizerPositionByDrag(event) { const { tableContainerEl, isColumnResizing, currentResizingColumn, } = this if (tableContainerEl && isColumnResizing) { const { left: tableContainerLeft } = tableContainerEl.getBoundingClientRect() if (isColumnResizing && currentResizingColumn) { const { columnResizerStartX, columnMinWidth } = this // 不允许拖动小于列最小宽度 if ( currentResizingColumn._realTimeWidth + (event.clientX - columnResizerStartX) > columnMinWidth ) { this.columnResizerRect.left = event.clientX - tableContainerLeft } } } }, // column resizer handler mousedown columnResizerHandlerMousedown({ event }) { if (this.isColumnResizerHover) { this.setIsColumnResizing(true) // add document mousemove listener document.addEventListener( 'mousemove', this.setColumnResizerPositionByDrag, ) // add document mouseup listener document.addEventListener('mouseup', this.columnResizerMouseup) // stop text select when reszing document.onselectstart = function () { return false } document.ondragstart = function () { return false } } }, // column resizer mouseup columnResizerMouseup(event) { const { isColumnResizing, currentResizingColumn, columnResizerStartX, setColumnWidth, columnWidthResizeOption, columnMinWidth, } = this if (!isColumnResizing || !currentResizingColumn) { return false } let differWidth // 拖动小于列最小宽度 if ( currentResizingColumn._realTimeWidth + (event.clientX - columnResizerStartX) < columnMinWidth ) { differWidth = columnMinWidth - currentResizingColumn._realTimeWidth } else { differWidth = event.clientX - columnResizerStartX } differWidth = Math.floor(differWidth) // 偏差阈值,低于则不处理 if (Math.abs(differWidth) > 1) { let nextColumnWidth = currentResizingColumn._realTimeWidth nextColumnWidth += differWidth // set column width setColumnWidth({ colKey: currentResizingColumn.key, width: nextColumnWidth, }) if (columnWidthResizeOption) { const { sizeChange } = columnWidthResizeOption sizeChange && sizeChange({ column: currentResizingColumn, differWidth, columnWidth: nextColumnWidth, }) } } this.clearColumnResizerStatus() // add document mousemove listener document.removeEventListener( 'mousemove', this.setColumnResizerPositionByDrag, ) // add document mouseup listener document.removeEventListener('mouseup', this.columnResizerMouseup) }, // clear column resizer status clearColumnResizerStatus() { this.currentResizingColumn = null this.columnResizerStartX = 0 this.setIsColumnResizerHover(false) this.setIsColumnResizing(false) // enable text select when reszing document.onselectstart = function () { return true } document.ondragstart = function () { return true } }, }, render() { const { isColumnResizerHover, isColumnResizing, columnResizerRect, columnResizerHandlerWidth, } = this const { left, top, height } = columnResizerRect const columnResizerHandlerProps = { class: { [clsName('column-resizer-handler')]: true, active: isColumnResizerHover || isColumnResizing, }, style: { left: left - columnResizerHandlerWidth + 'px', top: top + 'px', height: height + 'px', }, onClick: () => { // }, onMousedown: (event) => { this.columnResizerHandlerMousedown({ event }) }, onMouseenter: () => { this.setIsColumnResizerHover(true) }, onMouseleave: () => { this.setIsColumnResizerHover(false) }, onMouseup: (event) => { this.columnResizerMouseup(event) }, } const columnResizerLineProps = { class: [clsName('column-resizer-line')], style: { display: isColumnResizing ? 'block' : 'none', left: left + 'px', }, } return ( <div class={clsName('column-resizer')}> <div {...columnResizerHandlerProps} /> <div {...columnResizerLineProps} /> </div> ) }, }