vue3+ant-design-vue4.x+sortablejs 实现可拖拽行表格
sortablejs网址:sortablejs.com/
npm安装 npm install sortablejs --save

js
<template>
<div class="draggable-table-wrapper">
<a-table
ref="tableRef"
:columns="columns"
:data-source="tableData"
row-key="id"
:pagination="false"
class="draggable-table"
>
<!-- 可根据需要添加操作列 -->
<template #action="{ record }">
<a-button size="small" type="text" @click="handleView(record)"> 查看 </a-button>
</template>
</a-table>
</div>
</template>
<script setup>
import { ref, onMounted, nextTick, watch } from 'vue'
import { Table, Card, Button, message } from 'ant-design-vue'
import Sortable from 'sortablejs'
// 表格数据
const tableData = ref([
{ id: '1', name: '张三', age: 28, department: '产品部', email: 'zhangsan@example.com' },
{ id: '2', name: '李四', age: 32, department: '开发部', email: 'lisi@example.com' },
{ id: '3', name: '王五', age: 25, department: '设计部', email: 'wangwu@example.com' },
{ id: '4', name: '赵六', age: 35, department: '测试部', email: 'zhaoliu@example.com' },
{ id: '5', name: '钱七', age: 29, department: '市场部', email: 'qianqi@example.com' },
{ id: '6', name: '孙八', age: 31, department: '开发部', email: 'sunba@example.com' },
{ id: '7', name: '周九', age: 27, department: '产品部', email: 'zhoujiu@example.com' }
])
// 表格列定义
const columns = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
width: 120
},
{
title: '年龄',
dataIndex: 'age',
key: 'age',
width: 80
},
{
title: '部门',
dataIndex: 'department',
key: 'department',
width: 120
},
{
title: '邮箱',
dataIndex: 'email',
key: 'email'
},
{
title: '操作',
key: 'action',
width: 100,
slots: { customRender: 'action' }
}
]
// 分页配置
const pagination = ref({
pageSize: 5,
showSizeChanger: true,
pageSizeOptions: ['5', '10', '20'],
showTotal: (total) => `共 ${total} 条记录`
})
// 表格引用
const tableRef = ref()
// 最后更新时间
const lastUpdated = ref('')
// 排序实例
let sortableInstance = null
// 初始化拖拽功能
const initSortable = () => {
// 确保先销毁已存在的实例
if (sortableInstance) {
sortableInstance.destroy()
}
nextTick(() => {
// 获取表格的tbody元素
const tableBody = tableRef.value.$el.querySelector('.ant-table-tbody')
console.log(tableBody, tableRef.value, tableRef.value.$el, tableRef.value.table, 'tableBody')
if (tableBody) {
// 初始化Sortable
sortableInstance = new Sortable(tableBody, {
animation: 150, // 动画时间
delay: 100, // 延迟开始拖拽,防止误操作
delayOnTouchOnly: true,
ghostClass: 'sortable-ghost', // 拖拽时的占位元素样式
chosenClass: 'sortable-chosen', // 选中元素的样式
dragClass: 'sortable-drag', // 拖拽元素的样式
onStart: () => {},
onEnd: (evt) => {
const { oldIndex, newIndex } = evt
// 处理拖拽结束后的逻辑
if (oldIndex !== newIndex && oldIndex !== undefined && newIndex !== undefined) {
// 复制原数据并调整顺序
const newData = [...tableData.value]
const [movedItem] = newData.splice(oldIndex, 1)
newData.splice(newIndex, 0, movedItem)
// 更新数据
tableData.value = newData
// 更新最后操作时间
lastUpdated.value = new Date().toLocaleString()
// 这里可以添加保存到服务器的逻辑
// saveNewOrder(newData.map(item => item.id));
}
}
})
}
})
}
// 监听分页变化,重新初始化拖拽
watch(
() => pagination.value.current,
() => {
initSortable()
}
)
watch(
() => pagination.value.pageSize,
() => {
initSortable()
}
)
// 组件挂载时初始化拖拽
onMounted(() => {
initSortable()
})
// 查看详情
const handleView = (record) => {
message.info(`查看 ${record.name} 的详情`)
// 这里可以添加查看详情的逻辑
}
</script>
<style scoped>
:deep(.ant-table-tbody > tr) {
&:hover {
td {
cursor: move;
&:first-child {
&::before {
content: '';
position: absolute;
left: 0;
top: 0;
width: 20px;
height: 56px;
background: url('@/pc/assets/images/tableDrag.svg');
background-size: 100% 100%;
}
}
}
}
}
</style>