ant design vue组件库中的table实现拖拽行排序功能

在Vue3和AntDesignVue的TypeScript项目中,通过自定义表格行实现拖拽排序功能,关键代码包括对鼠标事件的监听(onDragstart,onDragover,onDrop)以及数据源的更新操作。遇到sortablejs等插件使用问题,采用手动实现成功解决。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述:在vue3+ant design vue+ts的项目中遇到了需要实现表格拖拽行进行排序的功能,翻遍了第三方插件使用未果,例如sortablejs,失败案例就不在此处过多赘述了,直接展示成功的写法,希望可以帮到有类似功能的朋友。

<Table
      :dataSource="dataSource"
      :columns="columns"
      showIndexColumn
      :customRow="customRow"
      size="small"
    >
      <template #action="{ record }">
        <Button type="link">删除</Button>
        <Button type="link" v-if="record.type == '0'">隐藏</Button>
        <Button type="link" v-else>取消隐藏</Button>
      </template>
    </Table>
 引入
 import { Table, Button } from 'ant-design-vue';

主要代码
// 位置记录
  const position = {
    start: undefined as number | undefined,
    end: undefined as number | undefined,
    sourceEl: undefined as undefined | HTMLTableRowElement,
  };
  // 排序
  const reorder = ({ start, end }) => {
    console.log('676868', start, end);
    if (start !== undefined && end !== undefined) {
      if (start > end) {
        // 当开始大于结束
        let temp = dataSource.value[start];
        dataSource.value.splice(start, 1);
        dataSource.value.splice(end, 0, temp);
      } else if (start < end) {
        // 结束大于开始
        let temp = dataSource.value[start];
        dataSource.value.splice(start, 1);
        dataSource.value.splice(end + 1, 0, temp);
      }
      let arr: string[] = dataSource.value?.map((item: any) => item.id);
      emit('onDeviceList', arr);
    }
  };
  function customRow(_record, index) {
    return {
      style: {
        cursor: 'move',
      },
      // 鼠标移入
      onMouseenter: (event) => {
        // 兼容IE
        let ev = event || window.event;
        ev.target.draggable = true;
      },
      // 开始拖拽
      onDragstart: (event) => {
        // 兼容IE
        let ev = event || window.event;
        // 阻止冒泡
        ev.stopPropagation();
        // 得到源目标数据;
        position.start = index;
        const tr = ev.target as HTMLTableRowElement;
        position.sourceEl = tr;
      },
      // 拖动元素经过的元素
      onDragover: (event) => {
        let ev = event || window.event;
        // 阻止默认行为
        ev.preventDefault();
      },
      // 松开
      onDrop: (event) => {
        let ev = event || window.event;
        // 阻止默认行为
        ev.preventDefault();
        position.end = index;
        reorder(position);
        animation(position);
      },
    };
  }
  // 实现动画效果
  function animation({ start, end, sourceEl }) {
    // 48 是每行的高度,也可以自动获取,根据情况而定
    let count = 48 * (start! - end!);
    sourceEl.style.translate = `0px ${count}px`;
    setTimeout(() => {
      sourceEl!.style.transition = 'all 0.5s';
      sourceEl!.style.translate = `0px 0px`;
    });
  }

此案例代码亲测有用

实现两个table相互拖拽排序可以使用ant-design-vue的`<a-transfer>`组件。具体实现步骤如下: 1. 使用`<a-transfer>`组件分别渲染两个table,设置`:data-source`和`:target-keys`属性。 ``` <a-transfer :data-source="leftTableData" :target-keys="leftSelectedKeys" :render="item => item.title" :operations="['>', '<']" :list-style="{'width': '200px'}" ></a-transfer> <a-transfer :data-source="rightTableData" :target-keys="rightSelectedKeys" :render="item => item.title" :operations="['>', '<']" :list-style="{'width': '200px'}" ></a-transfer> ``` 2. 监听`change`事件,实现数据的拖拽操作。 ``` <a-transfer :data-source="leftTableData" :target-keys="leftSelectedKeys" :render="item => item.title" :operations="['>', '<']" :list-style="{'width': '200px'}" @change="handleTransferChange" ></a-transfer> <a-transfer :data-source="rightTableData" :target-keys="rightSelectedKeys" :render="item => item.title" :operations="['>', '<']" :list-style="{'width': '200px'}" @change="handleTransferChange" ></a-transfer> ``` ``` methods: { handleTransferChange (nextTargetKeys, direction, moveKeys) { const { leftTableData, rightTableData } = this if (direction === 'right') { const moveData = leftTableData.filter(item => moveKeys.includes(item.key)) this.rightTableData = rightTableData.concat(moveData) this.leftTableData = leftTableData.filter(item => !moveKeys.includes(item.key)) } else if (direction === 'left') { const moveData = rightTableData.filter(item => moveKeys.includes(item.key)) this.leftTableData = leftTableData.concat(moveData) this.rightTableData = rightTableData.filter(item => !moveKeys.includes(item.key)) } } } ``` 3. 根据需要自定义样式和数据源。 完整代码示例: ``` <template> <div> <a-transfer :data-source="leftTableData" :target-keys="leftSelectedKeys" :render="item => item.title" :operations="['>', '<']" :list-style="{'width': '200px'}" @change="handleTransferChange" ></a-transfer> <a-transfer :data-source="rightTableData" :target-keys="rightSelectedKeys" :render="item => item.title" :operations="['>', '<']" :list-style="{'width': '200px'}" @change="handleTransferChange" ></a-transfer> </div> </template> <script> export default { data () { return { leftTableData: [ { key: '1', title: '项目1' }, { key: '2', title: '项目2' }, { key: '3', title: '项目3' }, { key: '4', title: '项目4' } ], rightTableData: [ { key: '5', title: '项目5' }, { key: '6', title: '项目6' }, { key: '7', title: '项目7' }, { key: '8', title: '项目8' } ], leftSelectedKeys: [], rightSelectedKeys: [] } }, methods: { handleTransferChange (nextTargetKeys, direction, moveKeys) { const { leftTableData, rightTableData } = this if (direction === 'right') { const moveData = leftTableData.filter(item => moveKeys.includes(item.key)) this.rightTableData = rightTableData.concat(moveData) this.leftTableData = leftTableData.filter(item => !moveKeys.includes(item.key)) } else if (direction === 'left') { const moveData = rightTableData.filter(item => moveKeys.includes(item.key)) this.leftTableData = leftTableData.concat(moveData) this.rightTableData = rightTableData.filter(item => !moveKeys.includes(item.key)) } } } } </script> ```
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值