基于ant-design-vue 1x表格组件实现列伸缩功能

前言

        ant-design-vue1x官方文档推荐集成vue-draggable-resizable来实现表格的可伸缩列,但是官方demo有bug,且使用起来很麻烦,所以自己动手在ant-design-vue 1x表格组件的基础上实现列伸缩功能。

实现列伸缩功能的思路

        在每个th里添加一个元素用来左右拖动列,通过absolute定位将拖动元素其定位到th的右边界处。给拖动元素绑定mousedown事件,在mousedown时开始给document绑定move事件监测左右拖动的距离,根据拖动距离设置当前拖动元素对应的th的宽度,设置th列宽可通过设置colgroup里的col的宽度来实现。

关键代码

        表格使用的是template风格的API。

<a-table-column
    v-for="(column, columnIdx) in columnsMap"
    :key="column.dataIndex"
    :align="column.align"
    :dataIndex="column.dataIndex"
    :width="column.width"
    :fixed="column.fixed">
    <!-- 表格 thead -->
    <template #title>
      <div class="column-title">
        <div @mousedown="e => handleColumnResize(e, columnIdx, column.dataIndex)" class="column-resize"></div>
      </div>
    </template>
</a-table-column>

        鼠标拖动事件处理

handleColumnResize(clickE, index, dataIndex) {
	this.movingColumnKey = dataIndex

	let originX = clickE.pageX
	let moveX = 0
	document.onmousemove = e => {
		// 在拖动列时保持鼠标指针的样式
		document.body.style.cursor = 'col-resize'

		moveX = e.pageX - originX
		if (moveX != 0) {
			let colIndex = index
			let length = 0
			const refContainer = this.$refs.table
			if (this.elColgroupList?.length > 0) {
				length = this.elColgroupList.length
			} else {
				// 列拉伸收缩-获取所有col
				this.elColgroupList = refContainer.getElementsByTagName('colgroup')
			}

			let computedMoveX = 0 // 实际的伸缩量
			let finalWidth = 0 // 最终宽度
			for (let i=0 ; i<length; i++) {
				const group = this.elColgroupList[i]
				if (group?.childNodes?.[colIndex]){
					const target = group.childNodes[colIndex]

					let currentW = target.style.width // 样式设置的宽度

					const viewWidth = target.getBoundingClientRect().width // 实际视图的宽度
					if (currentW) {
						// 去除单位
						currentW = parseInt(currentW.slice(0, -2))
					} else {
						currentW = viewWidth
					}

					// columnMinWidth为定义的最小列宽,防止列宽过小
					if ((viewWidth + moveX) <= this.columnMinWidth) {
						target.style.width = `${this.columnMinWidth}px`
						target.style.minWidth = `${this.columnMinWidth}px`
						target.width = this.columnMinWidth

						computedMoveX = this.columnMinWidth - currentW
						finalWidth = this.columnMinWidth
					} else {
						const movedW = currentW + moveX

						target.style.width = `${movedW}px`
						target.style.minWidth = `${movedW}px`
						target.width = movedW

						computedMoveX = moveX
						finalWidth = movedW
					}
				}
			}

			// 如果列宽变化,同步更改表格宽度,不压缩其他列
			if (this.elScrollTableList?.length === 0) {
				const elScroll = refContainer.getElementsByClassName('ant-table-scroll')?.[0]
				if (elScroll) {
					this.elScrollTableList = elScroll.getElementsByTagName('table')
				}
			}
			const tabLength = this.elScrollTableList.length
			for (let i=0 ; i<tabLength; i++) {
				const table = this.elScrollTableList[i]
				const widthStr = table?.style?.width || ''
				const len = widthStr.length
				if (len > 2) {
					const width = parseInt(widthStr.slice(0, len - 2))
					table.style.width = `${width + computedMoveX}px`
				}
			}

			const myEvent = new Event('resize')
			setTimeout(() => {
				window.dispatchEvent(myEvent)
			}, 10)

			originX = e.pageX
		}

	}
	// mouseup或mouseleave事件,取消拖动列
	document.onmouseup = e => {
		document.body.style.cursor = 'auto'
		this.movingColumnKey = ''

		document.onmousemove = null
		document.onmouseup = null
	}
	document.onmouseleave = e => {
		document.body.style.cursor = 'auto'
		document.onmousemove = null
		document.onmouseleave = null
	}
},

总结

        上面提到的列伸缩是在每个th内部右边界处添加一个元素用于拖动,拖动时只是增大或减小当前th的宽度,最右一列的宽度伸缩也是在右边界处拖动。固定列需要固定宽度,没有支持伸缩。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值