React ant组件下实现滚轮控制table表格行宽度,非hooks

在这里插入图片描述
如图可以看到表头文字太多了,
本来想实现table拖拽控制宽度,类似element那样,然后找了半天插件,发现大部分都是自己封装,然后引入的,没有简单的直接上手使用的,考虑了半天想到了一个曲线救国的方式:
那就是利用Column的width去控制表格的行宽,大家都知道Column是可以设置width,于是就想到了这个办法,这个办法虽然也有点复杂,不过至少不用动源码,话不多说,简单描述下。
第一步:首先需要将每个Column的width都写上,如下代码:

<Column width={this.state.tableWidthData[7].w}  ellipsis={true} align='center' title="供应商" dataIndex="supplier" key="supplier" />

如果你的Column是个数据集,不是我这种直接写出来的也是可以利用这种方法,也是一样的做法。

第二步:模拟width数据填充到Column,width上,可能有人注意到了this.state.tableWidthData,先看下这个东西是什么,如下代码:

tableWidthData:[
			{
				w:null,
				s:null,
				t:0
			},
			{
				w:100,
				s:100,
				t:0
			},
			{
				w:null,
				s:null,
				t:0
			},

w:后面会用这个去更新宽度,s:默认的宽度,null就是自由缩放,t:我是用来做点击控制宽度的,点一下展开,再点一下恢复,如果不需要可以不用。表头有几个需要写多少。

注意:想看封装版的可以直接拉到下边,这里不是封装版,不便于复用

第三步:写事件,想控制header,肯定需要先获取到我点的是谁,给谁缩放宽度,这里我们利用table的一个事件:

<Table onHeaderRow={(columns, index)=>{
								return {
								      onClick: (e)=>{this.onHeaderRow(e,columns, index)},
									  onMouseWheel: (e)=>{this.onMouseWheel(e,columns, index)},
									  onMouseEnter: (e) => {this.onMouseEnter(e,columns, index)}, // 鼠标移入行
									  onMouseLeave: (e) => {this.onMouseLeave(e,columns, index)},
								    };
							}}

好了,看到这步应该大概都知道怎么做了吧,话不多说,上代码:

onMouseEnter(e,columns, index){
			let selectTitle = e.target.innerText
			if(!selectTitle){
				return
			}
			let selectedIndex = null
			columns.map((v,i)=>{
				if(v.title === selectTitle){
					selectedIndex = i -1
				}
			})
			this.setState({
				selectedIndex:selectedIndex,
				saveThis:this
			},()=>{
				window.onmousewheel = document.onmousewheel = (e)=>{this.onMouseWheel(e,this.state.saveThis)}
			})
			
		};
		onMouseLeave(){
			window.onmousewheel = document.onmousewheel = null;
		};
		onMouseWheel(e,saveThis){
			let that = saveThis
			e = e || window.event;
			let tableWidthData = Object.assign([],that.state.tableWidthData)
		  let w = tableWidthData[that.state.selectedIndex].w?tableWidthData[that.state.selectedIndex].w:0
		  let th = document.getElementsByClassName('ant-table-thead')[0].childNodes[0].childNodes
		  let wdith = th[that.state.selectedIndex + 1].offsetWidth
		  console.log(wdith)
		  w = w?w:wdith
		  if(e.wheelDelta){ //IE/Opera/Chrome
			console.log(e.wheelDelta); // +150表示向上;-150表示向下
			if(e.wheelDelta > 0){
				w++
			}else{
				if(w > 0){
					w--
				}
			}
		  } else if (e.detail) {  //Firefox滑轮事件
			 console.log(e.detail); // +3表示向上;-3表示向下
			 if(e.wheelDelta > 0){
			 	w++
			 }else{
			 	if(w > 0){
			 		w--
			 	}
			 }
		  }
		  tableWidthData[that.state.selectedIndex].w = w
		  
		  that.setState({
			 tableWidthData:tableWidthData 
		  })
		  console.log(w)
		};

onMouseEnter:鼠标移入事件
selectTitle :获取到你当前触摸的是谁,取得其实是table的title
selectedIndex:保存下你当前点击的下标,等下在tableWidthData 使用
saveThis:保存下this,因为在滚轮事件获取不到this
onMouseLeave:鼠标离开事件
取消下滚轮事件就可以,没什么说的
onMouseWheel:滚轮事件
tableWidthData :这个就是第二部自定义的数据
w:就是tableWidthData 里的默认宽度
th:获取下头部的th
wdith:本来想直接用w的,后来发现老是突然没了,其实是w太小了,最后获取了下th,然后先获取下初始宽度给w
如果后面不生效,可以等w赋值完,再用setState赋值下table的数据

注意下:这种方式有个缺点,那就是触摸只有离开表头才会再次触发,挺难受的,后来我是加了一个点击去获取当前下标是那个。也就是图上的click。

其实利用这种方式也是可以做拖动的,既然滚轮都可以,其他肯定也是可以的,不过需求没那么多,而且挺复杂,懒得搞了。

补丁:
上边说触摸的问题,导致只能下去,上来才能选中下一个,目前找到了一个方法可以解决:

componentDidMount(){
			let th = document.getElementsByClassName('ant-table-thead')[0].childNodes[0].childNodes
				th.forEach((v)=>{
					v.onmouseenter = this.onmouseenter.bind(this)
				})


onmouseenter(e){
			if(!this.state.saveColumns) return
			let selectTitle = e.target.innerText
			console.log(selectTitle)
			if(!selectTitle){
				return
			}
			let selectedIndex = null
			this.state.saveColumns.map((v,i)=>{
				if(v.title === selectTitle){
					selectedIndex = i -1
				}
			})
			this.setState({
				selectedIndex:selectedIndex,
			})
		};

saveColumns:这个需要在上边代码onMouseEnter这个事件去赋值下。

this.setState({
				selectedIndex:selectedIndex,
				saveThis:this,
				saveColumns:columns
			},()=>{
				window.onmousewheel = document.onmousewheel = (e)=>{this.onMouseWheel(e,this.state.saveThis)}
			})

好了,目前对于滚轮控制行的宽高没什么问题了。


因为上边的有点复杂,而且不利于复用,所以这里封装了下,便于其他界面复用,原理都是一样的,以上代码第一步,第二步不变,基础数据还是要先搞好,然后以上其他代码都已经没用了

简化后第三步:

<Table onHeaderRow={(columns, index)=>{
								return {
									  onMouseEnter: (e)=>{
										  React.isWheel(e,columns,Object.assign([],this.state.tableWidthData) ,(d)=>{
										  	console.log(d)
										  	this.setState({
										  		tableWidthData:[...d]
										  	})
										  })
									  }, // 鼠标移入行
									  onMouseLeave: ()=>{window.onmousewheel = document.onmousewheel = null},
								    };
							}}

React.isWheel:这个是我把封装的函数isWheel放在React对象里,你可以不用这样写,随便放个地方,引用下就可以
tableWidthData:同样需要把基础数据传进去

简化后第四步,直接把封装的代码找个地方放就可以了,然后引用过来,像上图那样调用下,就可以了

function isWheel(e,columns,tableWidthData,callback){
	
	let state = {
		selectedIndex:null,
		saveColumns:null,
		tableWidthData:tableWidthData,
		thNodes:[]
	}
	const onMouseEnter = (e,columns)=>{
		let selectTitle = e.target.innerText
		console.log(selectTitle)
		if(!selectTitle){
			return
		}
		let selectedIndex = null
		columns.map((v,i)=>{
			if(v.title === selectTitle){
				selectedIndex = i -1
			}
		})
		state.selectedIndex = selectedIndex,
		state.saveColumns = columns
		window.onmousewheel = document.onmousewheel = (e)=>{onMouseWheel(e)}
		if(state.thNodes.length === 0){
			state.thNodes = document.getElementsByClassName('ant-table-thead')[0].childNodes[0].childNodes
			state.thNodes.forEach((v)=>{
				v.onmouseenter = (e)=>onmouseenter(e)
			})
		}
		
		
	}
	const onmouseenter = (e)=>{
		if(!state.saveColumns) return
		let selectTitle = e.target.innerText
		console.log(selectTitle)
		if(!selectTitle){
			return
		}
		let selectedIndex = null
		state.saveColumns.map((v,i)=>{
			if(v.title === selectTitle){
				selectedIndex = i -1
			}
		})
		state.selectedIndex = selectedIndex
	}
	const onMouseWheel = (e)=>{
		e = e || window.event;
		let w = state.tableWidthData[state.selectedIndex].w?state.tableWidthData[state.selectedIndex].w:0
		let th = document.getElementsByClassName('ant-table-thead')[0].childNodes[0].childNodes
		let width = th[state.selectedIndex + 1].offsetWidth
		console.log(width)
		w = w?w:width
		if(e.wheelDelta){ //IE/Opera/Chrome
			console.log(e.wheelDelta); // +150表示向上;-150表示向下
			if(e.wheelDelta > 0){
				w = w + 3
			}else{
				if(w > 0){
					w = w - 3
				}
			}
		} else if (e.detail) {  //Firefox滑轮事件
			 console.log(e.detail); // +3表示向上;-3表示向下
			 if(e.wheelDelta > 0){
				w = w + 3
			 }else{
				if(w > 0){
					w = w - 3
				}
			 }
		}
		state.tableWidthData[state.selectedIndex].w = w
		
		callback(state.tableWidthData)
		
	}
	
	
	onMouseEnter(e,columns)
	
	
}

注意下:我这是一个界面一个表格的情况,如果一个界面多个表格,上边的document.getElementsByClassName(‘ant-table-thead’)[0]这块0需要简单改下,dom获取下传过来就可以了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值