vue2版本可以参考当前vue3的优化
element plus
使用sortablejs 实现拖拽排序
pnpm add sortablejs
// ts类型文件
pnpm add @types/sortablejs -D
<template>
<el-table
v-loading="loading"
ref="tableRef"
:data="tableData"
style="width: 100%"
row-key="id"
border
lazy
:load="load"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
@expand-change="handleExpand"
:expand-row-keys="expandRowKeys"
:row-class-name="rowClassName"
>
<el-table-column prop="date" label="Date" />
<el-table-column prop="name" label="Name" />
<el-table-column prop="address" label="Address" />
</el-table>
</template>
<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue'
import Sortable from 'sortablejs'
interface User {
id: string
date: string
name: string
address: string
hasChildren?: boolean
children?: User[]
isFirst?: boolean
}
const tableData = ref<User[]>([])
const expandRowKeys = ref<string[]>([])
const loading = ref<boolean>(false)
const tableRef = ref(null)
const load = (row: User, _treeNode: unknown, resolve: ((date: User[]) => void) | undefined) => {
// 模拟后台返回的数据
setTimeout(() => {
const loadData = [
{
id: `${row.id}-31`,
date: '2016-05-01',
name: `${row.id}-name`,
address: 'No. 189, Grove St, Los Angeles'
},
{
id: `${row.id}-32`,
date: '2016-05-01',
name: `${row.id}-name`,
address: 'No. 189, Grove St, Los Angeles'
}
]
resolve?.(loadData)
}, 1000)
}
// 遍历一级数据手动添加 isFirst 字段,用于添加类名,用于排序,和设置expand-row-keys (展开行的key)
const data: User[] = [
{
id: '1',
date: '2016-05-02',
name: 'wangxiaohu',
address: 'No. 189, Grove St, Los Angeles',
isFirst: true
},
{
id: '2',
date: '2016-05-04',
name: 'wangxiaohu',
hasChildren: true,
address: 'No. 189, Grove St, Los Angeles',
isFirst: true
},
{
id: '3',
date: '2016-05-01',
name: 'wangxiaohu',
hasChildren: true,
address: 'No. 189, Grove St, Los Angeles',
isFirst: true
},
{
id: '4',
date: '2016-05-03',
name: 'wangxiaohu',
hasChildren: true,
address: 'No. 189, Grove St, Los Angeles',
isFirst: true
}
]
// 模拟排序后的数据
const data2: User[] = [
{
id: '1',
date: '2016-05-02',
name: 'wangxiaohu',
address: 'No. 189, Grove St, Los Angeles',
isFirst: true
},
{
id: '3',
date: '2016-05-01',
name: 'wangxiaohu',
hasChildren: true,
address: 'No. 189, Grove St, Los Angeles',
isFirst: true
},
{
id: '4',
date: '2016-05-03',
name: 'wangxiaohu',
hasChildren: true,
address: 'No. 189, Grove St, Los Angeles',
isFirst: true
},
{
id: '2',
date: '2016-05-044',
name: 'wangxiaohu',
hasChildren: true,
address: 'No. 189, Grove St, Los Angeles',
isFirst: true
}
]
const rowClassName = ({ row }: { row: User }) => {
// 给第一级行 设置类名 用于sortable的draggable字段,指定类可排序
if (row?.isFirst) {
return 'sortItem'
}
return ''
}
const handleExpand = (row: User, expanded: boolean) => {
// 一级行实现手风琴
if (row?.isFirst) {
expandRowKeys.value = expanded ? [row.id] : []
}
}
const rowDrop = () => {
const tbody = document.querySelector('.el-table__body-wrapper tbody') as HTMLElement
Sortable.create(tbody, {
draggable: '.sortItem', // 拥有sortItem类名的行才能排序
onStart: function () {
// 拖拽开始收起所有张开的行
expandRowKeys.value = []
},
onEnd(evt: any) {
// newDraggableIndex , oldDraggableIndex 是可拖拽元素的下标,更具这两个下表获取id,传递给后端排序,重新获取数据
// const { newDraggableIndex, oldDraggableIndex } = evt
// const fromId = tableData.value[evt.oldDraggableIndex].id
// const toId = tableData.value[evt.newDraggableIndex].id
// 清空数据,重新渲染node,处理数据节点复用,视图未更新的问题
tableData.value = []
nextTick(() => {
// 下次渲染更新数据
loading.value = true
setTimeout(() => {
tableData.value = data2
loading.value = false
}, 200)
})
}
})
}
onMounted(() => {
// 首次加载获取数据
loading.value = true
setTimeout(() => {
tableData.value = data
loading.value = false
}, 3000)
// 拖拽处理
document.body.ondrop = function (event) {
event.preventDefault()
event.stopPropagation()
}
// 拖拽功能与配置
rowDrop()
})
</script>