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

该功能存在bug哦,移步我的新博客:vxe-table 鼠标滑动选择多行,鼠标区域选中批量操作[2]_wanghanlu_的博客-CSDN博客

在看vxe-table 文档时,发现一个功能,鼠标区域选中,觉得这个功能很好。

 但是仔细发现,这个功能不是免费的。我就想想,为啥不能自己实现呢。

下面给你看看我的最终效果:

可复制、粘贴、数值自增。

 实现步骤

<template>
	//其他相关配置省略 这里的ref名称需要注意
	<vxe-grid ref='xGrid' v-bind="gridOptions" @cell-click="tableCellClick">
	</vxe-grid>
</template>

<style scoped>
	.vxe-grid{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
	.td-mouse-active{background-color:rgb(155,204,255) !important}
</style>

JS:

<script>
	export default {
		data() {
			return {
				gridOptions:
				{
					size:
					"small",
					border: "full",
					//斑马纹
					stripe: true,
				},
				//鼠标区域选中
				selectedCells: [],
				// 选中的单元格数组
				isSelecting: false,
				// 是否正在进行选择操作
				selectionStart: {
					rowIndex: -1,
					cellIndex: -1
				},
				// 选择操作起始单元格位置
				selectionEnd: {
					rowIndex: -1,
					cellIndex: -1
				},
				// 选择操作结束单元格位置
			}
		},
		mounted() {
			this.init();
		},
		methods: {
			init() {
				let column = [{
					width: 80,
					field: "id",
					title: "id"
				},
				{
					width: 80,
					field: "name",
					title: "姓名"
				}];
				this.getTablexGrid().loadColumn(column);
				this.getTablexGrid().loadData([{
					id: 1,
					name: "whl"
				},
				{
					id: 2,
					name: "aoliao"
				}]);
				this.$nextTick(() = >{
					let tbody = this.getTablexGrid().$el.querySelector("table tbody");
					if (tbody) {
						//主要给表体添加事件
						tbody.addEventListener("mousedown", this.tbodymousedown);
						tbody.addEventListener("mouseup", this.tbodymouseup);
						tbody.addEventListener("mousemove", this.tbodymousemove);
						tbody.addEventListener("paste", this.tbodykeydown);
					}
				})
			},
			getTablexGrid() {
				return this.$refs.xGrid;
			},
			//表格单元格点击事件
			tableCellClick(e) {
				if (!this.isSelecting) {
					this.selectionStart = this.getCellPosition(e.$event.target);
					// this.selectionStart = { rowIndex:-1, cellIndex:-1};
					this.selectionEnd = this.selectionStart;
					//设置样式
					this.setselectedCellArea();
				}
				this.$emit("cell-click", e);
			},
			init() {
				let column = [{
					width: 80,
					field: "id",
					title: "id"
				},
				{
					width: 80,
					field: "name",
					title: "姓名"
				}];
				this.getTablexGrid().loadColumn(column);
				this.getTablexGrid().loadData([{
					id: 1,
					name: "whl"
				},
				{
					id: 2,
					name: "aoliao"
				}]);
				this.$nextTick(() = >{
					let tbody = this.getTablexGrid().$el.querySelector("table tbody");
					if (tbody) {
						//主要给表体添加事件
						tbody.addEventListener("mousedown", this.tbodymousedown);
						tbody.addEventListener("mouseup", this.tbodymouseup);
						tbody.addEventListener("mousemove", this.tbodymousemove);
						tbody.addEventListener("paste", this.tbodykeydown);
					}
				})
			},
			tbodymousedown(event) {
				//一定是左键左键
				if (event.button === 0) {
					// 记录选择操作起始位置
					this.selectionStart = this.getCellPosition(event.target);
					this.isSelecting = true;
				}
			},
			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;
					// 记录选择操作结束位置
					this.selectionEnd = this.getCellPosition(event.target);
					//设置样式
					this.setselectedCellArea();
				}
			},
			tbodymouseup() {
				//左键
				if (event.button === 0) {
					this.isSelecting = false;
				}
			},
			// 获取单元格位置
			getCellPosition(cell) {
				while (cell.tagName !== 'TD') {
					cell = cell.parentElement;
				}
				const rowIndex = cell.parentElement.rowIndex;
				const cellIndex = cell.cellIndex;
				return {
					rowIndex,
					cellIndex
				};
			},
			//设置单元格选中样式
			setselectedCellArea() {
				let startRowIndex = this.selectionStart["rowIndex"];
				let endRowIndex = this.selectionEnd["rowIndex"];
				let startColumnIndex = this.selectionStart["cellIndex"];
				let endColumnIndex = this.selectionEnd["cellIndex"];

				let tbody = this.getTablexGrid().$el.querySelector("table tbody");
				let trs = tbody.getElementsByTagName("tr");
				for (var i = 0; i < trs.length; i++) {
					let tr = trs[i];
					let tds = tr.getElementsByTagName("td");
					for (var j = 0; j < tds.length; j++) {
						let td = tds[j];
						if (startRowIndex <= i && endRowIndex >= i && startColumnIndex <= j && endColumnIndex >= j) {
							td.classList.add("td-mouse-active");
						} else {
							td.classList.remove("td-mouse-active");
						}
					}
				}
			},

		}

	}
</script>

经过上面的代码,已经可以显示我们鼠标选中的区域了。

 接下来实现复制、粘贴、数值自增功能

选中的单元格的起始位置保存在selectionStart 里,结束位置保存在selectionEnd里

后续操作中根据位置获取行和列

行要用getTableData()["tableData"],

列要用getTableColumn()["tableColumn"]

首先要给vxe-grid 添加按键事件

<vxe-grid ref='xGrid' v-bind="gridOptions" height="300px"
		@cell-click="tableCellClick" 
        @keydown="tableKeydown">
        <!-- keydown 事件 -->
</vxe-grid>

添加如下方法

//复制需要用到 
import XEClipboard from 'xe-clipboard';
tableKeydown({$event}) {
	let event = $event;
	if (event.ctrlKey && event.keyCode === 67) {
		//ctrl+c 复制
		this.exec_commod("copy");
		event.preventDefault();
	} else if (event.ctrlKey && event.keyCode === 86) {
		//ctrl+v 粘贴
		this.exec_commod("paset") event.preventDefault();
	} else if (event.ctrlKey && event.key === 'z') {
		//ctrl+z
		this.exec_commod("cellSortValue") event.preventDefault();
	}
},
exec_commod(code) {
	let startRowIndex = this.selectionStart["rowIndex"];
	let endRowIndex = this.selectionEnd["rowIndex"];
	let startColumnIndex = this.selectionStart["cellIndex"];
	let endColumnIndex = this.selectionEnd["cellIndex"];
	var tableData = this.getTablexGrid().getTableData()["tableData"];
	var tableColumn = JSON.parse(JSON.stringify(this.getTablexGrid().getTableColumn()["tableColumn"]));
	switch (code) {
		//复制
	case "copy":
		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);
		//
		if (XEClipboard.copy(finalStr)) {
			this.$VXETable.modal.message({
				content: '已复制到剪贴板!',
				status: 'success'
			});
		}
		break;
		//粘贴
	case "paset":
		//由于浏览器的安全策略,只能是本地环境或者是https才能获取到剪贴板内容
		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;
	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;
}