安装第三方拖拽库
npm install sortablejs --save
效果预览
代码实现
完整代码地址:gitee - 拖拽排序
<template>
<div class="drap-table-sort">
<!-- 一定要给 el-table 绑定唯一的 row-key, 否则行拖拽时页面上显示的顺序会有问题 -->
<el-table
:data="tableData"
stripe
style="width: 100%"
row-key="id">
<el-table-column
label=""
width="50"
class-name="drap-handle-cell">
<template #default="scoped">
<span class="drap-handle">三</span>
</template>
</el-table-column>
<el-table-column
v-for="(item, index) in colums"
:prop="item.prop"
:label="item.label"
width="180">
</el-table-column>
</el-table>
</div>
</template>
<script lang="ts" setup>
import Sortable from 'sortablejs';
import { onMounted, onUnmounted, ref } from 'vue';
const colums = ref([
{
label: 'date',
prop: 'date',
},
{
label: 'name',
prop: 'name',
},
{
label: 'address',
prop: 'address',
},
]);
const tableData = ref([
{
id: '0',
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
id: '1',
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
id: '2',
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
id: '3',
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
]);
// 处理 拖拽逻辑
const handleRowDrag = () => {
const tableBody = document.querySelector('.el-table__body-wrapper tbody') as HTMLElement;
Sortable.create(tableBody, {
animation: 150,
handle: '.drap-handle-cell',
direction: 'vertical',
scroll: true,
scrollSensitivity: 50,
forceFallback: true,
onStart: (event) => {
// scroll 设为 true 会导致拖拽时选中其他文本,
// 所以拖拽时禁用选中,拖拽完后恢复文本选择
document.body.style.userSelect = 'none';
},
onEnd: (event: Sortable.SortableEvent) => {
// 恢复文本选择
document.body.style.userSelect = '';
const moveItem = tableData.value.splice(event.oldIndex!, 1)[0];
tableData.value.splice(event.newIndex!, 0, moveItem);
},
});
};
const handleColDrag = () => {
const tableHeader = document.querySelector('.el-table__header-wrapper tr') as HTMLElement;
Sortable.create(tableHeader, {
animation: 150,
direction: 'horizontal',
onEnd: (event: Sortable.SortableEvent) => {
// 因为 table 中第一列是 拖动按钮,所以 table 的 item 比 colums 多一项
// index 是以 table 的列数为准的,所以需要 -1
const oldIndex = event.oldIndex! - 1
const newIndex = event.newIndex! - 1
const moveCol = colums.value.splice(oldIndex, 1)[0];
colums.value.splice(newIndex, 0, moveCol);
},
});
};
const originDrop = document.body.ondrop;
onMounted(() => {
// 据说 火狐浏览器 拖拽时会跳转到新的页面,所以这里先禁用默认事件
document.body.ondrop = function (event) {
event.preventDefault();
event.stopPropagation();
};
handleRowDrag();
handleColDrag();
});
onUnmounted(() => {
document.body.ondrop = originDrop;
});
</script>
<style lang="scss" scoped>
.drap-table-sort {
:deep(.el-table) {
.drap-handle-cell {
cursor: pointer;
}
}
}
</style>