vxe-grid表格实现行、列级拖拽排序

3,742 阅读2分钟

Video_2024-05-08_103023[00-00-00--00-00-10].gif

1. 安装拖拽插件

npm i sortablejs

2. 行拖拽示例代码

<template>
	<vxe-grid class="sortable-row-demo" ref="xGridTable" v-bind="options">
		<template #dragable_default>
			<span class="drag-btn">
				<i class="vxe-icon-send"></i>
			</span>
		</template>
	</vxe-grid>
</template>
<script>
	import Sortable from 'sortablejs';
	export default {
		name: 'sortTable',
		components: {},
		props: {},
		data() {
			return {
				sortable: null,
				options: {
					border: true,
					resizable: true,
					rowConfig: { useKey: true }, //非常重要!!!
					data: [
						{ id: 10001, name: 'Test1', nickname: 'T1', role: 'Develop', sex: '0', sex2: ['0'], num1: 40, age: 28, address: 'Shenzhen', date12: '', date13: '' },
						{ id: 10002, name: 'Test2', nickname: 'T2', role: 'Designer', sex: '1', sex2: ['0', '1'], num1: 44, age: 22, address: 'Guangzhou', date12: '', date13: '2020-08-20' },
						{ id: 10003, name: 'Test3', nickname: 'T3', role: 'Test', sex: '0', sex2: ['1'], num1: 200, age: 32, address: 'test abc', date12: '2020-09-10', date13: '' },
						{ id: 10004, name: 'Test4', nickname: 'T4', role: 'Designer', sex: '1', sex2: ['1'], num1: 30, age: 23, address: 'Shenzhen', date12: '', date13: '2020-12-04' },
						{ id: 10005, name: 'Test5', nickname: 'T5', role: 'Develop', sex: '0', sex2: ['1', '0'], num1: 20, age: 30, address: 'Shanghai', date12: '2020-09-20', date13: '' },
						{ id: 10006, name: 'Test6', nickname: 'T6', role: 'Designer', sex: '1', sex2: ['0'], num1: 10, age: 21, address: 'Shenzhen', date12: '', date13: '' },
						{ id: 10007, name: 'Test7', nickname: 'T7', role: 'Develop', sex: '0', sex2: ['0'], num1: 5, age: 29, address: 'test abc', date12: '2020-01-02', date13: '2020-09-20' },
						{ id: 10008, name: 'Test8', nickname: 'T8', role: 'PM', sex: '1', sex2: ['0'], num1: 2, age: 35, address: 'Shenzhen', date12: '', date13: '' }
					],
					columns: [
						{
							title: '',
							fixed: 'left',
							width: 50,
							align: 'center',
							slots: {
								default: 'dragable_default'
							}
						},
						{ type: 'radio', width: 50 },
						{ type: 'seq', width: 60 },
						{ field: 'name', title: 'Name' },
						{ field: 'nickname', title: 'Nickname' },
						{ field: 'role', title: 'Role' },
						{ field: 'address', title: 'Address', showOverflow: true }
					]
				}
			};
		},
		computed: {},
		created() {
			this.rowDrop();
		},
		beforeDestroy() {
			if (this.sortable) {
				this.sortable.destroy();
			}
		},
		mounted() {},
		destroyed() {},
		methods: {
			rowDrop() {
				this.$nextTick(() => {
					const xGTable = this.$refs.xGridTable;
					this.sortable = Sortable.create(xGTable.$el.querySelector('.body--wrapper>.vxe-table--body tbody'), {
						handle: '.drag-btn',
						onEnd: ({ newIndex, oldIndex }) => {
							const currRow = this.options.data.splice(oldIndex, 1)[0];
							this.options.data.splice(newIndex, 0, currRow);
							this.$nextTick(() => {
								console.log(this.$refs.xGridTable.getTableData().tableData.map(row => row.name));
							});
						}
					});
				});
			}
		}
	};
</script>
<style lang="scss" scoped>
	.alert-message {
		height: 40px;
		display: flex;
		align-items: center;
		margin: 10px 0;
		border-radius: 4px;
		background-color: #e6f7ff;
		border: 1px solid #91d5ff;
	}
	.alert-message-icon {
		width: 30px;
		text-align: center;
		color: #409eff;
		margin-right: 8px;
	}
	.alert-message-content {
		flex-grow: 1;
		padding-right: 20px;
	}
</style>
<style>
	.sortable-row-demo .drag-btn {
		cursor: move;
		font-size: 12px;
	}
	.sortable-row-demo .vxe-body--row.sortable-ghost,
	.sortable-row-demo .vxe-body--row.sortable-chosen {
		background-color: #dfecfb;
	}
</style>

参考地址: vxetable.cn/other3/#/ta…

3. 列拖拽示例代码

<template>
	<vxe-grid ref="xGrid" v-bind="gridOptions"></vxe-grid>
</template>
<script>
	import Sortable from 'sortablejs';
	import VXETable from 'vxe-table';
	export default {
		data() {
			return {
				gridOptions: {
					border: true,
					showFooter: true,
					class: 'sortable-column-demo',
					columnConfig: {
						useKey: true,
						minWidth: 200
					},
					scrollX: {
						enabled: false
					},
					footerMethod: this.footerMethod,
					toolbarConfig: {
						custom: true
					},
					columns: [
						{ field: 'name', title: 'Name', fixed: 'left', width: 300 },
						{ field: 'nickname', title: 'Nickname' },
						{ field: 'role', title: 'Role' },
						{ field: 'sex', title: 'Sex' },
						{ field: 'age', title: 'Age' },
						{ field: 'date3', title: 'Date' },
						{ field: 'address', title: 'Address', width: 200, fixed: 'right', showOverflow: true }
					],
					data: [
						{ id: 10001, name: 'Test1', nickname: 'T1', role: 'Develop', sex: 'Man', age: 28, address: 'Shenzhen' },
						{ id: 10002, name: 'Test2', nickname: 'T2', role: 'Test', sex: 'Women', age: 22, address: 'Guangzhou' },
						{ id: 10003, name: 'Test3', nickname: 'T3', role: 'PM', sex: 'Man', age: 32, address: 'Shanghai' },
						{ id: 10004, name: 'Test4', nickname: 'T4', role: 'Designer', sex: 'Women', age: 23, address: 'Shenzhen' },
						{ id: 10005, name: 'Test5', nickname: 'T5', role: 'Develop', sex: 'Women', age: 30, address: 'Shanghai' }
					]
				}
			};
		},
		created() {
			this.columnDrop();
		},
		beforeDestroy() {
			if (this.sortable) {
				this.sortable.destroy();
			}
		},
		methods: {
			meanNum(list, field) {
				let count = 0;
				list.forEach(item => {
					count += Number(item[field]);
				});
				return count / list.length;
			},
			sumNum(list, field) {
				let count = 0;
				list.forEach(item => {
					count += Number(item[field]);
				});
				return count;
			},
			footerMethod({ columns, data }) {
				return [
					columns.map((column, columnIndex) => {
						if (columnIndex === 0) {
							return '平均';
						}
						if (['age', 'sex'].includes(column.property)) {
							return this.meanNum(data, column.property);
						}
						return null;
					}),
					columns.map((column, columnIndex) => {
						if (columnIndex === 0) {
							return '和值';
						}
						if (['age', 'sex'].includes(column.property)) {
							return this.sumNum(data, column.property);
						}
						return null;
					})
				];
			},
			columnDrop() {
				this.$nextTick(() => {
					const $table = this.$refs.xGrid;
					this.sortable = Sortable.create($table.$el.querySelector('.body--wrapper>.vxe-table--header .vxe-header--row'), {
						handle: '.vxe-header--column',
						onEnd: ({ item, newIndex, oldIndex }) => {
							const { fullColumn, tableColumn } = $table.getTableColumn();
							const targetThElem = item;
							const wrapperElem = targetThElem.parentNode;
							const newColumn = fullColumn[newIndex];
							if (newColumn.fixed) {
								const oldThElem = wrapperElem.children[oldIndex];
								// 错误的移动
								if (newIndex > oldIndex) {
									wrapperElem.insertBefore(targetThElem, oldThElem);
								} else {
									wrapperElem.insertBefore(targetThElem, oldThElem ? oldThElem.nextElementSibling : oldThElem);
								}
								VXETable.modal.message({ content: '固定列不允许拖动,即将还原操作!', status: 'error' });
								return;
							}
							// 获取列索引 columnIndex > fullColumn
							const oldColumnIndex = $table.getColumnIndex(tableColumn[oldIndex]);
							const newColumnIndex = $table.getColumnIndex(tableColumn[newIndex]);
							// 移动到目标列
							const currRow = fullColumn.splice(oldColumnIndex, 1)[0];
							fullColumn.splice(newColumnIndex, 0, currRow);
							$table.loadColumn(fullColumn);
						}
					});
				});
			}
		}
	};
</script>
<style>
	.sortable-column-demo .vxe-header--row .vxe-header--column.sortable-ghost,
	.sortable-column-demo .vxe-header--row .vxe-header--column.sortable-chosen {
		background-color: #dfecfb;
	}
	.sortable-column-demo .vxe-header--row .vxe-header--column.col--fixed {
		cursor: no-drop;
	}
</style>

参考地址:vxetable.cn/other3/#/ta…