vxe-table 鼠标滑动选择多行,鼠标区域选中批量操作[2]

这篇具有很好参考价值的文章主要介绍了vxe-table 鼠标滑动选择多行,鼠标区域选中批量操作[2]。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前几天写了一个关于 vxe-table 鼠标滑动选择多行 的博客,在项目上线的过程中,发现这个功能还是有点bug,在经过我对vxe-table pro版本 的演示后vxe-table PRO,认真调试后,终于解决了bug,并且这个功能和pro版本可以说是几乎一模一样。注意:我是说这个滑动选择的功能,不是说是pro版本的所有功能,哈哈哈。

我VUE用的是2.x版本.

如果是VUE是3版本,请参考下面这篇博客。

Vue3 vxe-table 手写鼠标区域选中-CSDN博客

下面是官网的pro版本示例

vxe-table,vxe-table,vue.js,前端,javascript

这是我的示例,是不是感觉一样呢。demo 看在线演示。

vxe-table,vxe-table,vue.js,前端,javascript

 接下来我来展示我的实现方法。

先说下思路吧:

1.鼠标滑动时显示的那个框,实际上是一个 div,所以需要定义div。

2.用户进行滑动操作,肯定需要给表格添加鼠标移动监听事件。

3.用户从什么时候位置开始移动鼠标,什么时候结束移动鼠标。需要记录那个框的开始位置和结束位置。

4.最后在用户鼠标移动结束后,显示这个框就行了。

开始实现:

1.先来一个最基础的vxe-grid表格,相信大家都清楚吧。

<template>
	<div>
<!-- 注意这里的ref名称,后续都会用到的 -->
		<vxe-grid ref='xGrid' v-bind="gridOptions" height="400px">
			
		</vxe-grid>
	</div>
</template>

<script>
	export default {
		data() {
			return{
				gridOptions:{
					//行配置,这里的行高一定需要指定
					"row-config":{isCurrent:true,height:35},
					//左上角按钮
					toolbarConfig:{
						perfect: true,
						enabled:true,
						size:"mini",
						buttons:[
							{
								code:'getcellselctdata',type:"text",name:'获取选中数据'
							}
						],
					},
					//列配置 (使用列拖拽功能,必须配置useKey为true)
					"column-config":{resizable:true,useKey:true},
					//边框
					border:"full",
					//斑马纹
					stripe:true,
					//列信息
					columns:[
						{width:70,field:"id",title:"#",align:"left",fixed:"left"},
						{width:100,field:"name",title:"姓名",align:"left",fixed:"left"},
						{width:100,field:"age",title:"年龄",align:"left",fixed:"left"},
						{width:100,field:"sex",title:"性别",align:"left"},
						{width:100,field:"job",title:"岗位",align:"left"},
						{width:270,field:"address",title:"地址",align:"left"},
					],
					//数据
					data:[
						{id:1,name:"张三",age:30,sex:"男",job:"前端",address:"中国xxxxxxxxxx"},
						{id:2,name:"李四",age:30,sex:"男",job:"后端",address:"中国xxxxxxxxxx"},
						{id:3,name:"王五",age:30,sex:"女",job:"运维",address:"中国xxxxxxxxxx"},
						{id:4,name:"赵六",age:30,sex:"男",job:"美工",address:"中国xxxxxxxxxx"},
						{id:5,name:"老八",age:30,sex:"男",job:"项目经理",address:"中国xxxxxxxxxx"},
						{id:6,name:"桀桀",age:30,sex:"女",job:"售后",address:"中国xxxxxxxxxx"},
					],
					//这里一定要指定true,否则row-config的height没用
					'show-overflow':true,
					//行配置,这里的行高一定需要指定
					"row-config":{isCurrent:true,height:35,isHover:true},
				},
			}
		},
		mounted() {
		},
		methods: {
		}
	}
</script>

<style scoped>

</style>

显示的效果是这样的(下图),并且滑动选中是浏览器默认的选中效果。

vxe-table,vxe-table,vue.js,前端,javascript

 2.清除浏览器的默认选中行为:

.vxe-grid{
		-webkit-user-select: none; /* Safari */
		-moz-user-select: none; /* Firefox */
		-ms-user-select: none; /* Internet Explorer/Edge */
		user-select: none;
	}

加上这个css代码,这样在鼠标选中时就不会出现刚刚那个蓝色的背景色了,这一步很重要哦。

需要全局的也可以写到app.vue中。

3.定义div。也就是我所说的框。并且在官网示例中也是这样做的,大家可以放心。

我这里是定义了两个框。分为非fixed和fixed区域的框。

<!-- 注意这里的ref名称,后续都会用到的 -->
<!-- 正常区域的框 -->
		<div class="vxe-table--cell-area" ref="cellarea">
			<span class="vxe-table--cell-main-area"></span>
			<span class="vxe-table--cell-active-area"></span>
		</div>
<!-- 注意这里的ref名称,后续都会用到的 -->
		<!-- 左边fixed区域的框,右边fixed没有尝试过。。。 -->
		<div class="vxe-table--cell-area" ref="fixedcellarea">
			<span class="vxe-table--cell-main-area"></span>
			<span class="vxe-table--cell-active-area"></span>
		</div>

vxe-table,vxe-table,vue.js,前端,javascript

4.给表格添加监听(用户鼠标操作),记录用户鼠标开始操作的位置和结束的位置。

在data中定义所需的变量,记录用户鼠标滑动开始位置和结束位置。

isSelecting: false, // 是否正在进行选择操作
				selectionStart:{rowIndex:-1,cellIndex:-1}, // 选择操作起始单元格位置
				selectionEnd:{rowIndex:-1,cellIndex:-1}, // 选择操作结束单元格位置

 然后给表格添加事件监听(这里的代码不做过多的解释,大家可以看看注释):

methods里面是11个方法,在mounted里面调用addListener方法就欧克了。

vxe-table,vxe-table,vue.js,前端,javascript

 接下来给出这11个方法的代码,有兴趣的可以自己的需求进行修改。

//返回table的ref名称
			getTablexGrid(){
				return this.$refs.xGrid;
			},
			//添加事件
			addListener(){
				//添加多选列
				this.$nextTick(()=>{
					let tbody=this.getTablexGrid().$el.querySelector(".vxe-table--main-wrapper table tbody");
					if(tbody){
						tbody.addEventListener("mousedown",this.tbodymousedown);
						tbody.addEventListener("mouseup",this.tbodymouseup);
						tbody.addEventListener("mousemove",this.tbodymousemove);
					}
					let bodyWrapper=this.getTablexGrid().$el.querySelector(".vxe-table--main-wrapper .vxe-table--body-wrapper");
					if(bodyWrapper){
						//注意这里的ref名称,这里是非fixed区域的框的名称
						bodyWrapper.appendChild(this.$refs.cellarea);
					}
					
					setTimeout(()=>{
						let fixedtbody=this.getTablexGrid().$el.querySelector(".vxe-table--fixed-wrapper table tbody");
						if(fixedtbody){
							fixedtbody.addEventListener("mousedown",this.tbodymousedown);
							fixedtbody.addEventListener("mouseup",this.tbodymouseup);
							fixedtbody.addEventListener("mousemove",this.tbodymousemove);
						}
						
						let fixedBodyWrapper=this.getTablexGrid().$el.querySelector(".vxe-table--fixed-wrapper .vxe-table--body-wrapper");
						if(fixedBodyWrapper){
							//注意这里的ref名称,这里是fixed区域的框的名称
							fixedBodyWrapper.appendChild(this.$refs.fixedcellarea);
						}
					})
				})
			},
			//鼠标按下事件
			tbodymousedown(event){
				//左键
				if(event.button === 0){
					// 记录选择操作起始位置
					this.selectionStart = this.getCellPosition(event.target);
					this.isSelecting = true;
				}
			},
			//鼠标移动事件
			tbodymousemove(event){
				//左键
				if(event.button === 0){
					if (!this.isSelecting) return;
					var x = event.clientX;
					// 记录选择操作结束位置
					this.selectionEnd = this.getCellPosition(event.target);
					//设置样式
					this.setselectedCellArea();
					//持续向右滚动
					var x = event.clientX;
					var table=this.getTablexGrid().$el.querySelector(".vxe-table--body-wrapper table");
					if(table){
						let tableRect=table.parentElement.getBoundingClientRect();
						if (x > tableRect.right - 20){
							table.parentElement.scrollLeft+=20;
						}
					}
				}
			},
			//鼠标按键结束事件
			tbodymouseup(event) {
				//左键
				if(event.button === 0){
					this.isSelecting = false;
				}
			},
			// 获取单元格位置
			getCellPosition(cell) {
				try{
					while(cell.tagName !== 'TD'){
						cell = cell.parentElement;
					}
					// const rowIndex = cell.parentElement.rowIndex;
					// const cellIndex = cell.cellIndex;
					let visibleColumn=this.getTablexGrid().getTableColumn()["visibleColumn"];
					const cellIndex = visibleColumn.findIndex((col)=>{
						return col.id==cell.getAttribute("colid");
					})
					let visibleData=this.getTablexGrid().getTableData()["visibleData"];
					const rowIndex =visibleData.findIndex((row)=>{
						return row._X_ROW_KEY==cell.parentElement.getAttribute("rowid");
					})
					return { rowIndex, cellIndex };
				}catch(e){
					return { rowIndex:-1,cellIndex:-1};
				}
			},
			//设置框打开
			setselectedCellArea(){
				let startRowIndex=this.selectionStart["rowIndex"];
				let endRowIndex=this.selectionEnd["rowIndex"];
				let startColumnIndex=this.selectionStart["cellIndex"];
				let endColumnIndex=this.selectionEnd["cellIndex"];
				let {width,height,left,top}=this.getAreaBoxPostion();
				// .vxe-table--fixed-wrapper .vxe-table--body-wrapper
				// .vxe-table--main-wrapper .vxe-table--body-wrapper
				var activeElement=this.getTablexGrid().$el.querySelector(".vxe-table--main-wrapper .vxe-table--body-wrapper .vxe-table--cell-active-area");
				var mainElement=this.getTablexGrid().$el.querySelector(".vxe-table--main-wrapper .vxe-table--body-wrapper .vxe-table--cell-main-area");
				var fixedActiveElement=this.getTablexGrid().$el.querySelector(".vxe-table--fixed-wrapper .vxe-table--body-wrapper .vxe-table--cell-active-area");
				var fixedMainElement=this.getTablexGrid().$el.querySelector(".vxe-table--fixed-wrapper .vxe-table--body-wrapper .vxe-table--cell-main-area");
				//获取固定列宽度fixed--hidden
				var fixedWidth=0;
				let flexDiv=this.getTablexGrid().$el.querySelector(".vxe-table--fixed-left-wrapper");
				if(flexDiv){
					fixedWidth=flexDiv.offsetWidth;
				}
				var elements=[activeElement,mainElement,fixedActiveElement,fixedMainElement];
				elements.forEach((element)=>{
					if(element){
						element.style.width=`${width}px`;
						element.style.height=`${height}px`;
						element.style.top=`${top}px`;
						element.style.left=`${left}px`;
						element.style.display="block";
					}
				})
				this.openAreaBox();
				this.selectionStart={"cellIndex":startColumnIndex,"rowIndex":startRowIndex};
				this.selectionEnd={"cellIndex":endColumnIndex,"rowIndex":endRowIndex};
			},
			//根据开始位置和结束位置的索引计算框的width,height,left,top
			getAreaBoxPostion(){
				let startRowIndex=this.selectionStart["rowIndex"];
				let endRowIndex=this.selectionEnd["rowIndex"];
				let startColumnIndex=this.selectionStart["cellIndex"];
				let endColumnIndex=this.selectionEnd["cellIndex"];
				let visibleColumn=this.getTablexGrid().getTableColumn()["visibleColumn"];
				let visibleData=this.getTablexGrid().getTableData()["visibleData"];
				if(startColumnIndex<0||endColumnIndex<0||startRowIndex<0||endRowIndex<0)return;
				var maxColumnIndex=visibleColumn.length-1;
				var maxRowIndex=visibleData.length-1;
				if(endColumnIndex>maxColumnIndex){
					endColumnIndex=maxColumnIndex;
				}
				if(endRowIndex>maxRowIndex){
					endRowIndex=maxRowIndex;
				}
				// height width left top display
				// cellarea
				let width=0,height=0,left=0,top=0;
				let fixedwidth=0,fixedheight=0,fixedleft=0,fixedtop=0;
				visibleColumn.forEach((col,index)=>{
					if(index<startColumnIndex){
						left+=this.getTablexGrid().getColumnWidth(col);
					}
					if(index<=endColumnIndex&&startColumnIndex<=index){
						width+=this.getTablexGrid().getColumnWidth(col);
					}
				})
				height=(endRowIndex-startRowIndex+1)*this.gridOptions["row-config"]["height"];
				if(height<=0||width<=0){
					this.destroyAreaBox();
					return;
				}
				top=startRowIndex*this.gridOptions["row-config"]["height"];
				return {width,height,left,top};
			},
			//显示范围框
			openAreaBox(){
				var element=this.$refs.xGrid.$el.querySelector(".vxe-table--main-wrapper .vxe-table--body-wrapper .vxe-table--cell-area");
				if(element){
					element.style.display="block";
				}
				element=this.$refs.xGrid.$el.querySelector(".vxe-table--fixed-wrapper .vxe-table--body-wrapper .vxe-table--cell-area");
				if(element){
					element.style.display="block";
				}
			},
			//关闭范围框
			closeAreaBox(){
				var element=this.getTablexGrid().$el.querySelector(".vxe-table--main-wrapper .vxe-table--body-wrapper .vxe-table--cell-area");
				if(element){
					element.style.display="none";
				}
				element=this.getTablexGrid().$el.querySelector(".vxe-table--fixed-wrapper .vxe-table--body-wrapper .vxe-table--cell-area");
				if(element){
					element.style.display="none";
				}
			},
			//销毁范围框
			destroyAreaBox(){
				this.selectionStart={"rowIndex":-1,"cellIndex":-1};
				this.selectionEnd={"rowIndex":-1,"cellIndex":-1};
				var element=this.getTablexGrid().$el.querySelector(".vxe-table--main-wrapper .vxe-table--body-wrapper .vxe-table--cell-area");
				if(element){
					element.style.display="none";
				}
				element=this.getTablexGrid().$el.querySelector(".vxe-table--fixed-wrapper .vxe-table--body-wrapper .vxe-table--cell-area");
				if(element){
					element.style.display="none";
				}
			},

文章到这,就实现了功能哦。

vxe-table,vxe-table,vue.js,前端,javascript

5.但是需要在加一个功能,用户点击表格单元格时需要关闭原先的框,显示用户点击单元格时的新框。这个可以说的不是很清楚,但是在你们使用时就会发现这个问题的。

vxe-table,vxe-table,vue.js,前端,javascript

 方法:

//表格单元格点击事件
			tableCellClick(e){
				let {row,column}=e;
				if(!this.isSelecting){
					if(!this.lastActive||this.lastActive["rowid"]!=row["_X_ROW_KEY"]||this.lastActive["colid"]!=column["id"]){
						this.selectionStart = this.getCellPosition(e.$event.target);
						this.selectionEnd =this.selectionStart;
						//设置样式
						this.setselectedCellArea();
						this.lastActive={"rowid":"","colid":""};
					}
				}
			},

6.那如何获取选中区域的数据呢?相信这是大家比较关心的问题吧。

						console.log("是否正在进行滑动选中操作:",this.isSelecting);
						//左上角坐标
						console.log("单元格起始位置:索引:",this.selectionStart);
						//右下角坐标
						console.log("单元格结束位置:索引:",this.selectionEnd);
						
						//这里需要是visibleData
						let tableData=this.getTablexGrid().getTableData()["visibleData"];
						let rowStart=this.selectionStart.rowIndex;
						let rowEnd=this.selectionEnd.rowIndex;
						let selectRows=tableData.filter((col,index)=>{
							return rowStart<=index&&rowEnd>=index;
						})
						console.log("鼠标选中行:",JSON.stringify(selectRows));
						
						//这里需要是visibleColumn
						let colStart=this.selectionStart.cellIndex;
						let colEnd=this.selectionEnd.cellIndex;
						let tableColumn=this.getTablexGrid().getTableColumn()["visibleColumn"];
						let selectCols=tableColumn.filter((col,index)=>{
							return colStart<=index&&colEnd>=index;
						})
						console.log("鼠标选中列:",JSON.stringify(selectCols));

下面给出整个示例的完整代码:文章来源地址https://www.toymoban.com/news/detail-755215.html

<template>
	<div style="width: 600px;">
		<!-- 正常区域的框 -->
		<div class="vxe-table--cell-area" ref="cellarea">
			<span class="vxe-table--cell-main-area"></span>
			<span class="vxe-table--cell-active-area"></span>
		</div>
		<!-- 左边fixed区域的框,右边fixed没有尝试过。。。 -->
		<div class="vxe-table--cell-area" ref="fixedcellarea">
			<span class="vxe-table--cell-main-area"></span>
			<span class="vxe-table--cell-active-area"></span>
		</div>
		
		<vxe-grid ref='xGrid' v-bind="gridOptions" height="400px"
			@cell-click="tableCellClick"
			@keydown="tableKeydown"
			@toolbar-button-click="toolbarButtonClickEvent">
			
		</vxe-grid>
	</div>
</template>

<script>
	import XEClipboard from 'xe-clipboard';
	export default {
		data() {
			return{
				gridOptions:{
					"keyboard-config":{
						isArrow: true,
					},
					//左上角按钮
					toolbarConfig:{
						perfect: true,
						enabled:true,
						size:"mini",
						buttons:[
							{
								code:'getcellselctdata',type:"text",name:'获取选中数据(结果看控制台)'
							}
						],
					},
					//列配置 (使用列拖拽功能,必须配置useKey为true)
					"column-config":{resizable:true,useKey:true},
					//边框
					border:"full",
					//斑马纹
					stripe:true,
					//列信息
					columns:[
						{width:70,field:"id",title:"#",align:"left",fixed:"left"},
						{width:100,field:"name",title:"姓名",align:"left",fixed:"left"},
						{width:100,field:"age",title:"年龄",align:"left",fixed:"left"},
						{width:100,field:"sex",title:"性别",align:"left"},
						{width:100,field:"job",title:"岗位",align:"left"},
						{width:270,field:"address",title:"地址",align:"left"},
					],
					//数据
					data:[
						{id:1,name:"张三",age:30,sex:"男",job:"前端",address:"中国xxxxxxxxxx"},
						{id:2,name:"李四",age:30,sex:"男",job:"后端",address:"中国xxxxxxxxxx"},
						{id:3,name:"王五",age:30,sex:"女",job:"运维",address:"中国xxxxxxxxxx"},
						{id:4,name:"赵六",age:30,sex:"男",job:"美工",address:"中国xxxxxxxxxx"},
						{id:5,name:"老八",age:30,sex:"男",job:"项目经理",address:"中国xxxxxxxxxx"},
						{id:6,name:"桀桀",age:30,sex:"女",job:"售后",address:"中国xxxxxxxxxx"},
					],
					//这里一定要指定true,否则row-config的height没用
					'show-overflow':true,
					//行配置,这里的行高一定需要指定
					"row-config":{isCurrent:true,height:35,isHover:true},
				},
				//鼠标滑动选中
				isSelecting: false, // 是否正在进行选择操作
				selectionStart:{rowIndex:-1,cellIndex:-1}, // 选择操作起始单元格位置
				selectionEnd:{rowIndex:-1,cellIndex:-1}, // 选择操作结束单元格位置
			}
		},
		mounted() {
			this.addListener();
		},
		methods: {
			//返回table的ref名称
			getTablexGrid(){
				return this.$refs.xGrid;
			},
			//添加事件
			addListener(){
				//添加多选列
				this.$nextTick(()=>{
					let tbody=this.getTablexGrid().$el.querySelector(".vxe-table--main-wrapper table tbody");
					if(tbody){
						tbody.addEventListener("mousedown",this.tbodymousedown);
						tbody.addEventListener("mouseup",this.tbodymouseup);
						tbody.addEventListener("mousemove",this.tbodymousemove);
						tbody.addEventListener("paste",this.tbodykeydown);
					}
					let bodyWrapper=this.getTablexGrid().$el.querySelector(".vxe-table--main-wrapper .vxe-table--body-wrapper");
					if(bodyWrapper){
						//注意这里的ref名称,这里是非fixed区域的框的名称
						bodyWrapper.appendChild(this.$refs.cellarea);
					}
					
					setTimeout(()=>{
						let fixedtbody=this.getTablexGrid().$el.querySelector(".vxe-table--fixed-wrapper table tbody");
						if(fixedtbody){
							fixedtbody.addEventListener("mousedown",this.tbodymousedown);
							fixedtbody.addEventListener("mouseup",this.tbodymouseup);
							fixedtbody.addEventListener("mousemove",this.tbodymousemove);
							fixedtbody.addEventListener("paste",this.tbodykeydown);
						}
						
						let fixedBodyWrapper=this.getTablexGrid().$el.querySelector(".vxe-table--fixed-wrapper .vxe-table--body-wrapper");
						if(fixedBodyWrapper){
							//注意这里的ref名称,这里是fixed区域的框的名称
							fixedBodyWrapper.appendChild(this.$refs.fixedcellarea);
						}
					})
				})
			},
			//鼠标按下事件
			tbodymousedown(event){
				//左键
				if(event.button === 0){
					// 记录选择操作起始位置
					this.selectionStart = this.getCellPosition(event.target);
					this.isSelecting = true;
				}
			},
			//鼠标移动事件
			tbodymousemove(event){
				//左键
				if(event.button === 0){
					if (!this.isSelecting) return;
					var x = event.clientX;
					// 记录选择操作结束位置
					this.selectionEnd = this.getCellPosition(event.target);
					//设置样式
					this.setselectedCellArea();
					//持续向右滚动
					var x = event.clientX;
					var table=this.getTablexGrid().$el.querySelector(".vxe-table--body-wrapper table");
					if(table){
						let tableRect=table.parentElement.getBoundingClientRect();
						if (x > tableRect.right - 20){
							table.parentElement.scrollLeft+=20;
						}
					}
				}
			},
			//鼠标按键结束事件
			tbodymouseup(event) {
				//左键
				if(event.button === 0){
					this.isSelecting = false;
				}
			},
			// 获取单元格位置
			getCellPosition(cell) {
				try{
					while(cell.tagName !== 'TD'){
						cell = cell.parentElement;
					}
					// const rowIndex = cell.parentElement.rowIndex;
					// const cellIndex = cell.cellIndex;
					let visibleColumn=this.getTablexGrid().getTableColumn()["visibleColumn"];
					const cellIndex = visibleColumn.findIndex((col)=>{
						return col.id==cell.getAttribute("colid");
					})
					let visibleData=this.getTablexGrid().getTableData()["visibleData"];
					const rowIndex =visibleData.findIndex((row)=>{
						return row._X_ROW_KEY==cell.parentElement.getAttribute("rowid");
					})
					return { rowIndex, cellIndex };
				}catch(e){
					return { rowIndex:-1,cellIndex:-1};
				}
			},
			//设置框打开
			setselectedCellArea(){
				try{
					let startRowIndex=this.selectionStart["rowIndex"];
					let endRowIndex=this.selectionEnd["rowIndex"];
					let startColumnIndex=this.selectionStart["cellIndex"];
					let endColumnIndex=this.selectionEnd["cellIndex"];
					let {width,height,left,top}=this.getAreaBoxPostion();
					// .vxe-table--fixed-wrapper .vxe-table--body-wrapper
					// .vxe-table--main-wrapper .vxe-table--body-wrapper
					var activeElement=this.getTablexGrid().$el.querySelector(".vxe-table--main-wrapper .vxe-table--body-wrapper .vxe-table--cell-active-area");
					var mainElement=this.getTablexGrid().$el.querySelector(".vxe-table--main-wrapper .vxe-table--body-wrapper .vxe-table--cell-main-area");
					var fixedActiveElement=this.getTablexGrid().$el.querySelector(".vxe-table--fixed-wrapper .vxe-table--body-wrapper .vxe-table--cell-active-area");
					var fixedMainElement=this.getTablexGrid().$el.querySelector(".vxe-table--fixed-wrapper .vxe-table--body-wrapper .vxe-table--cell-main-area");
					//获取固定列宽度fixed--hidden
					var fixedWidth=0;
					let flexDiv=this.getTablexGrid().$el.querySelector(".vxe-table--fixed-left-wrapper");
					if(flexDiv){
						fixedWidth=flexDiv.offsetWidth;
					}
					var elements=[activeElement,mainElement,fixedActiveElement,fixedMainElement];
					elements.forEach((element)=>{
						if(element){
							element.style.width=`${width}px`;
							element.style.height=`${height}px`;
							element.style.top=`${top}px`;
							element.style.left=`${left}px`;
							element.style.display="block";
						}
					})
					this.openAreaBox();
					this.selectionStart={"cellIndex":startColumnIndex,"rowIndex":startRowIndex};
					this.selectionEnd={"cellIndex":endColumnIndex,"rowIndex":endRowIndex};
				}catch(e){
				}
			},
			//根据开始位置和结束位置的索引计算框的width,height,left,top
			getAreaBoxPostion(){
				let startRowIndex=this.selectionStart["rowIndex"];
				let endRowIndex=this.selectionEnd["rowIndex"];
				let startColumnIndex=this.selectionStart["cellIndex"];
				let endColumnIndex=this.selectionEnd["cellIndex"];
				let visibleColumn=this.getTablexGrid().getTableColumn()["visibleColumn"];
				let visibleData=this.getTablexGrid().getTableData()["visibleData"];
				if(startColumnIndex<0||endColumnIndex<0||startRowIndex<0||endRowIndex<0)return;
				var maxColumnIndex=visibleColumn.length-1;
				var maxRowIndex=visibleData.length-1;
				if(endColumnIndex>maxColumnIndex){
					endColumnIndex=maxColumnIndex;
				}
				if(endRowIndex>maxRowIndex){
					endRowIndex=maxRowIndex;
				}
				// height width left top display
				// cellarea
				let width=0,height=0,left=0,top=0;
				let fixedwidth=0,fixedheight=0,fixedleft=0,fixedtop=0;
				visibleColumn.forEach((col,index)=>{
					if(index<startColumnIndex){
						left+=this.getTablexGrid().getColumnWidth(col);
					}
					if(index<=endColumnIndex&&startColumnIndex<=index){
						width+=this.getTablexGrid().getColumnWidth(col);
					}
				})
				height=(endRowIndex-startRowIndex+1)*this.gridOptions["row-config"]["height"];
				if(height<=0||width<=0){
					this.destroyAreaBox();
					return;
				}
				top=startRowIndex*this.gridOptions["row-config"]["height"];
				return {width,height,left,top};
			},
			//显示范围框
			openAreaBox(){
				var element=this.$refs.xGrid.$el.querySelector(".vxe-table--main-wrapper .vxe-table--body-wrapper .vxe-table--cell-area");
				if(element){
					element.style.display="block";
				}
				element=this.$refs.xGrid.$el.querySelector(".vxe-table--fixed-wrapper .vxe-table--body-wrapper .vxe-table--cell-area");
				if(element){
					element.style.display="block";
				}
			},
			//关闭范围框
			closeAreaBox(){
				var element=this.getTablexGrid().$el.querySelector(".vxe-table--main-wrapper .vxe-table--body-wrapper .vxe-table--cell-area");
				if(element){
					element.style.display="none";
				}
				element=this.getTablexGrid().$el.querySelector(".vxe-table--fixed-wrapper .vxe-table--body-wrapper .vxe-table--cell-area");
				if(element){
					element.style.display="block";
				}
			},
			//销毁范围框
			destroyAreaBox(){
				this.selectionStart={"rowIndex":-1,"cellIndex":-1};
				this.selectionEnd={"rowIndex":-1,"cellIndex":-1};
				var element=this.getTablexGrid().$el.querySelector(".vxe-table--main-wrapper .vxe-table--body-wrapper .vxe-table--cell-area");
				if(element){
					element.style.display="none";
				}
				element=this.getTablexGrid().$el.querySelector(".vxe-table--fixed-wrapper .vxe-table--body-wrapper .vxe-table--cell-area");
				if(element){
					element.style.display="none";
				}
			},
			//表格单元格点击事件
			tableCellClick(e){
				let {row,column}=e;
				if(!this.isSelecting){
					if(!this.lastActive||this.lastActive["rowid"]!=row["_X_ROW_KEY"]||this.lastActive["colid"]!=column["id"]){
						this.selectionStart = this.getCellPosition(e.$event.target);
						this.selectionEnd =this.selectionStart;
						//设置样式
						this.setselectedCellArea();
						this.lastActive={"rowid":"","colid":""};
					}
				}
			},
			
			toolbarButtonClickEvent({code,button}){
				switch(code){
					case "getcellselctdata":
						//我给大家打印处理:
						console.log("是否正在进行滑动选中操作:",this.isSelecting);
						//左上角坐标
						console.log("单元格起始位置:索引:",this.selectionStart);
						//右下角坐标
						console.log("单元格结束位置:索引:",this.selectionEnd);
						
						//这里需要是visibleData
						let tableData=this.getTablexGrid().getTableData()["visibleData"];
						let rowStart=this.selectionStart.rowIndex;
						let rowEnd=this.selectionEnd.rowIndex;
						let selectRows=tableData.filter((col,index)=>{
							return rowStart<=index&&rowEnd>=index;
						})
						console.log("鼠标选中行:",JSON.stringify(selectRows));
						
						//这里需要是visibleColumn
						let colStart=this.selectionStart.cellIndex;
						let colEnd=this.selectionEnd.cellIndex;
						let tableColumn=this.getTablexGrid().getTableColumn()["visibleColumn"];
						let selectCols=tableColumn.filter((col,index)=>{
							return colStart<=index&&colEnd>=index;
						})
						console.log("鼠标选中列:",JSON.stringify(selectCols));
						break;
				}
			},
			tableKeydown({$event}){
				this.tbodykeydown($event);
			},
			tbodykeydown(event){
				let tablexgrid=this.getTablexGrid();
				let tableColumn=this.getTablexGrid().getTableColumn()["visibleColumn"];
				let tableData=this.getTablexGrid().getTableData()["visibleData"];
				let startRowIndex=this.selectionStart["rowIndex"];
				let endRowIndex=this.selectionEnd["rowIndex"];
				let startColumnIndex=this.selectionStart["cellIndex"];
				let endColumnIndex=this.selectionEnd["cellIndex"];
				var maxColumnIndex=tableColumn.length-1;
				var maxRowIndex=tableData.length-1;
				var minColumnIndex=0;
				var minRowIndex=0;
				
				if (event.ctrlKey && event.keyCode === 67) {
					//ctrl+c 复制
					this.contextMenuClickEvent({menu:{code:"cellCopy"}});
					event.preventDefault();
				}else if(event.ctrlKey&&event.keyCode === 86){
					//ctrl+v 粘贴
					this.contextMenuClickEvent({menu:{code:"cellPaste"}});
					event.preventDefault();
				}else if(event.ctrlKey && event.key === 'd'){
					//ctrl+d
					this.contextMenuClickEvent({menu:{code:"cellLineCopy"}});
					event.preventDefault();
				}else if(event.key === 'Delete'){
					//delete
					this.contextMenuClickEvent({menu:{code:"cellDelete"}});
					event.preventDefault();
				}else if(event.ctrlKey && event.key === 'x'){
					//ctrl+x
					this.contextMenuClickEvent({menu:{code:"cellCut"}});
					event.preventDefault();
				}else if(event.ctrlKey && event.key === 'z'){
					//ctrl+z
					this.contextMenuClickEvent({menu:{code:"cellSortValue"}});
					event.preventDefault();
				}else if(event.keyCode===39){
					//右键 向右
					if(endColumnIndex+1<=maxColumnIndex){
						var currentRow=tablexgrid.getCurrentRecord();
						const rowIndex =tableData.findIndex((row)=>{
							return row._X_ROW_KEY==currentRow._X_ROW_KEY;
						})
						this.selectionStart={"cellIndex":endColumnIndex+1,"rowIndex":rowIndex};
						this.selectionEnd={"cellIndex":endColumnIndex+1,"rowIndex":rowIndex};
					}
					this.setselectedCellArea();
					this.tableScrollMove("right");
					event.preventDefault();
				}else if(event.keyCode===37){
					//左键 向左
					if(startColumnIndex-1>=minColumnIndex){
						var currentRow=tablexgrid.getCurrentRecord();
						const rowIndex =tableData.findIndex((row)=>{
							return row._X_ROW_KEY==currentRow._X_ROW_KEY;
						})
						this.selectionStart={"cellIndex":startColumnIndex-1,"rowIndex":rowIndex};
						this.selectionEnd={"cellIndex":startColumnIndex-1,"rowIndex":rowIndex};
					}
					this.setselectedCellArea();
					this.tableScrollMove("left");
					event.preventDefault();
				}else if(event.keyCode===38){
					//向上
					var currentRow=tablexgrid.getCurrentRecord();
					const rowIndex =tableData.findIndex((row)=>{
						return row._X_ROW_KEY==currentRow._X_ROW_KEY;
					})
					if(rowIndex-1>=minRowIndex){
						this.selectionStart={"cellIndex":startColumnIndex,"rowIndex":rowIndex-1};
						this.selectionEnd={"cellIndex":startColumnIndex,"rowIndex":rowIndex-1};
					}
					this.setselectedCellArea();
					//判断是否小于最小行的个数
					event.preventDefault();
				}else if(event.keyCode===40){
					//向下
					var currentRow=tablexgrid.getCurrentRecord();
					const rowIndex =tableData.findIndex((row)=>{
						return row._X_ROW_KEY==currentRow._X_ROW_KEY;
					})
					if(rowIndex+1<=maxRowIndex){
						this.selectionStart={"cellIndex":startColumnIndex,"rowIndex":rowIndex+1};
						this.selectionEnd={"cellIndex":startColumnIndex,"rowIndex":rowIndex+1};
					}
					this.setselectedCellArea();
					event.preventDefault();
				}
			},
			//控制滚动条,元素隐藏时滚动条自动滚动到显示的位置
			//move:快捷键左右时有效,其他无效
			tableScrollMove(move){
				let tableColumn=this.getTablexGrid().getTableColumn()["visibleColumn"];
				let tableData=this.getTablexGrid().getTableData()["visibleData"];
				let startRowIndex=this.selectionStart["rowIndex"];
				let endRowIndex=this.selectionEnd["rowIndex"];
				let startColumnIndex=this.selectionStart["cellIndex"];
				let endColumnIndex=this.selectionEnd["cellIndex"];
				
				let fixedWidth=0;
				
				//获取固定列宽度fixed--hidden
				let flexDiv=this.getTablexGrid().$el.querySelector(".vxe-table--fixed-left-wrapper");
				if(flexDiv){
					fixedWidth=flexDiv.offsetWidth;
				}
				//获取td
				var td;
				var tbody=this.getTablexGrid().$el.querySelector(".vxe-table--main-wrapper table tbody");
				if(tbody&&move=="left"){
					var column=tableColumn[startColumnIndex];
					td=tbody.querySelector(`td[colid="${column.id}"]`);
				}else if(tbody&&move=="right"){
					var column=tableColumn[endColumnIndex];
					td=tbody.querySelector(`td[colid="${column.id}"]`);
				}
				if(td){
				//判断是否隐藏
					var tdRect=td.getBoundingClientRect();
					var table=this.getTablexGrid().$el.querySelector(".vxe-table--body-wrapper table");
					if(table){
						let tableRect=table.parentElement.getBoundingClientRect();
						//需要减去左边固定列的宽度
						if (tdRect.top < tableRect.top ||tdRect.bottom > tableRect.bottom ||
						    tdRect.left < tableRect.left+fixedWidth ||tdRect.right > tableRect.right){
							if(move=="right"){
								table.parentElement.scrollLeft+=(tdRect.right-tableRect.right);
							}else if(move=="left"){
								table.parentElement.scrollLeft+=(tdRect.left-tableRect.left-fixedWidth);
							}
						  } else {
						    // console.log("该 td 元素未隐藏");
						  }
					}
				}
			},
			//
			contextMenuClickEvent({menu,row,column,rowIndex,columnIndex,$event}){
				let startRowIndex=this.selectionStart["rowIndex"];
				let endRowIndex=this.selectionEnd["rowIndex"];
				let startColumnIndex=this.selectionStart["cellIndex"];
				let endColumnIndex=this.selectionEnd["cellIndex"];
				var tableColumn=JSON.parse(JSON.stringify(this.getTablexGrid().getTableColumn()["visibleColumn"]));
				var tableData=this.getTablexGrid().getTableData()["visibleData"];
				switch(menu.code){
					//复制
					case "cellCopy":
						let enterStr="\r\n";
						let spaceStr="\t";
						let data=[];
						for(var i=startRowIndex;i<=endRowIndex;i++){
							let value=[];
							for(var j=startColumnIndex;j<=endColumnIndex;j++){
								value.push(tableData[i][tableColumn[j].field]);
							}
							data.push(value);
						}
						let finalStr=data.map((value)=>{
							return value.join(spaceStr);
						}).join(enterStr);
						this.copyValue(finalStr);
						break;
					//粘贴
					case "cellPaste":
						navigator.clipboard.readText().then((text)=>{
							if(text){
								//去除首尾换行
								text=text.replace(/^\r\n+|\r\n+$/g, '');
								var snsArr=text.split(/\r\n+/);
								var tArr=snsArr.map((value)=>{
									return value.split("\t");
								})
								for(var i=0;i<tArr.length;i++){
									let line=tArr[i];
									if(startRowIndex+i>tableData.length-1)break;
									let row=tableData[startRowIndex+i];
									for(var j=0;j<line.length;j++){
										if(startColumnIndex+j>tableColumn.length)break;
										let column=tableColumn[startColumnIndex+j];
										row[column.field]=line[j];
									}
								}
							}
						})
						break;
					//delete清除
					case "cellDelete":
						for(var i=startRowIndex;i<=endRowIndex;i++){
							if(i>tableData.length-1)break;
							for(var j=startColumnIndex;j<=endColumnIndex;j++){
								if(j>tableColumn.length-1)break;
								let row=tableData[i];
								let column=tableColumn[j];
								this.getTablexGrid().clearData(row,column.property);
							}
						}
						break;
					case "cellLineCopy":
						//第一行的值不变,后面的行等于第一行的值
						var firstRow=tableData[startRowIndex];
						for(var i=startRowIndex+1;i<=endRowIndex;i++){
							if(i>tableData.length-1)break;
							for(var j=startColumnIndex;j<=endColumnIndex;j++){
								if(j>tableColumn.length-1)break;
								tableData[i][tableColumn[j].field]=firstRow[tableColumn[j].field];
							}
						}
						break;
					case "cellCut":
						//剪切
						this.contextMenuClickEvent({menu:{code:"cellCopy"}});
						this.contextMenuClickEvent({menu:{code:"cellDelete"}});
						break;
					case "cellSortValue":
						//自增
						var firstRow=tableData[startRowIndex];
						for(var i=startRowIndex+1;i<=endRowIndex;i++){
							if(i>tableData.length-1)break;
							for(var j=startColumnIndex;j<=endColumnIndex;j++){
								if(j>tableColumn.length-1)break;
								let value=firstRow[tableColumn[j].field];
								if(!value)break;
								if(!isNaN(value)){
									tableData[i][tableColumn[j].field]=parseFloat(value)+(i-startRowIndex);
								}else{
									//最后一个字符
									let lastChar=value[value.length-1];
									//去除最后一个字符
									let nvalChar=value.slice(0, -1);
									if(/[a-zA-Z]/.test(lastChar)){
										let result =this.generateAlphabetChars(lastChar,i-startRowIndex+1);
										tableData[i][tableColumn[j].field]=nvalChar+result;
									}
								}
							}
						}
						break;
				}
			},
			//数据自增的工具方法
			generateAlphabetChars(c, shift){
				/**
				 * 将一个字符按照指定的偏移量进行移位
				 * @param {string} c 需要移位的字符
				 * @param {number} shift 移位的偏移量
				 * @returns {string} 移位后的字符
				 */
				// 将字符转换为 ASCII 码
				var asciiCode = c.charCodeAt(0);
				// 计算移位后的 ASCII 码
				var shiftedAsciiCode = asciiCode + shift;
				let flag = false;
				if (shiftedAsciiCode > 122) {
					shiftedAsciiCode -= 26;
				} else if (shiftedAsciiCode < 97) {
					shiftedAsciiCode += 26;
				}
				// 将 ASCII 码转换为字符
				const shiftedChar = String.fromCharCode(shiftedAsciiCode);
				return asciiCode + shift > 122 ? 'a' + shiftedChar: shiftedChar;
			},
			//复制的工具方法
			copyValue(value){
				if (XEClipboard.copy(value)) {
					this.$VXETable.modal.message({content: '已复制到剪贴板!',status:'success',duration:400});
				}
			},
		}
	}
</script>

<style scoped>
	.vxe-grid{
		-webkit-user-select: none; /* Safari */
		-moz-user-select: none; /* Firefox */
		-ms-user-select: none; /* Internet Explorer/Edge */
		user-select: none;
	}
</style>

到了这里,关于vxe-table 鼠标滑动选择多行,鼠标区域选中批量操作[2]的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • vxe-table中树形结构

    如图,同事让帮忙实现一个需求  从二级树节点开始,同时选中的只能有一个二级树节点,选中的二级树节点之下的子节点都可以被选中。否则不能被选中 直接上代码 需要注意的是,文中树状图传递的数据是打平的数据,设置代码是下图,而不是树状图!!  上述的这一点非常

    2024年02月10日
    浏览(43)
  • vxe-table实现表格行拖拽

    1.插件文档 vex-table:https://vxetable.cn/v3/#/table/base/basic sortablejs: http://www.sortablejs.com/ 2.引入插件 vxe-table: sortablejs: 3.核心拖拽函数 渲染问题解决方法链接:sortablejs拖拽列表渲染问题 4.全代码 全代码

    2024年02月16日
    浏览(48)
  • 关于vxe-table全局引入的问题

    主要讲解一下vxe-table全局引入然后使用碰到的问题 0:vxe-table的官网地址 1:基本环境 (1):vue版本为3.x以上(我的是3.2.13) (2): 依赖库:xe-utils 注意:这篇博客的是vue3的脚手架搭建的,如果需要看低版本,请点击这里 2:使用npm安装 3:package.json文件里面就会有以下内

    2024年02月11日
    浏览(40)
  • vxe-table 表格多选框回显

    1.弹框表格结构   a-modal               v-if=\\\"visibleQuality\\\"               title=\\\"请选择需要提高的能力素质要求\\\"               :maskClosable=\\\"false\\\"               :visible=\\\"visibleQuality switchStatus\\\"               @ok=\\\"handleOkQuality\\\"               @cancel=\\\"handleCancelQuality\\\"            

    2024年02月06日
    浏览(42)
  • vue最强table vxe-table 虚拟滚动列表 前端导出

    最近遇到个问题。后台一次性返回2万条列表数据。 并且需求要求所有数据必须全部展示,不能做假分页(不能优化了)。 这些数据的直接来源就是CS客户端。 他们做CS客户端就是一次性加载几万条数据不分页(说这是客户的要求)。 我体验了一把CS客户端,数万条数据放在

    2024年02月12日
    浏览(41)
  • vue表格插件vxe-table导出 excel

    vxe-table 默认支持导出 CSV、HTML、XML、TXT格式的文件,不支持 xlsx 文件 要想导出 xlsx 文件,需要使用 vxe-table-plugin-export-xlsx 依赖  参考:https://cnpmjs.org/package/vxe-table-plugin-export-xlsx/v/2.1.0-beta 1.安装  例子: 如果用最新版的,依赖,这样使用就会报错 Uncaught (in promise) 亲测2.2.2版

    2024年01月22日
    浏览(48)
  • vxe-table表格合并单元格和编辑

    //这是在vue上面引用vxe-table插件实现的,主要方法都设置在table中,mergeCells,tableData都是在vue页面的data初使化数据, :footer-method=“footerMethod”:尾部数据,:merge-footer-items=“mergeCells”:尾部合并单元格。vxe-table网址:https://vxetable.cn/#/table/advanced/footerSpan

    2023年04月09日
    浏览(46)
  • 前端基础(Element、vxe-table组件库的使用)

    前言:在前端项目中,实际上,会用到组件库里的很多组件,本博客主要介绍Element、vxe-table这两个组件如何使用。 目录 Element 引入element 使用组件的步骤 使用对话框的示例代码 效果展示  vxe-table 引入vxe-table 成果展示 总结 官网地址 Button 按钮 | Element Plus (element-plus.org) 在m

    2024年02月10日
    浏览(42)
  • vue3 + vxe-table 封装通用Grid业务组件

    视频DEMO 功能 基于vxe-table v4 / vxe-grid 全局注册组件 无需单独引入 动态按需引入样式vite-plugin-style-import 支持传入高度 | 默认自适应高度 自定义表头 slot,实现下拉、区间、日期,并对表头参数进行校验(数字、长度、指定格式等) 自定义工具栏工具列,重写自定义列配置项,实现拖拽

    2023年04月08日
    浏览(49)
  • vxe-table 小众但功能齐全的vue表格组件

    一个基于 vue 的 PC 端表格组件,除了一般表格支持的增删改查、排序、筛选、对比、树形结构、数据分页等,它还支持虚拟滚动、懒加载、打印导出、虚拟列表、虚拟滚动、模态窗口、自定义模板、渲染器、贼灵活的配置项、扩展接口等,特别是能支持类似excel表格操作方式

    2024年02月08日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包