vue3+ant-design-vue4.x+sortablejs 实现可拖拽行表格

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>
相关推荐
To_OC7 小时前
别再串行写 await 了,Promise.all 才是并行请求的正确打开方式
前端·javascript·promise
vipbic8 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy8 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志8 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble9 小时前
c端系统,其实更像一个信息展示平台
前端
李姆斯10 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
名字还没想好☜11 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司11 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能
kaiking_g12 小时前
vue项目中,静态导入 vs 动态导入 详解
前端·javascript·vue.js
江华森12 小时前
Web 开发基础:HTTP 与 REST
前端·网络协议·http