Vue3 使用ant design vue table组件实现自定义拖拽效果

代码运行效果图

 <template>
    <!-- 使用 customRow 方法设置行属性 -->
    <a-table
        :columns="staffColumnsSort"
        :dataSource="dataSource"
        :rowKey="record => record.staffId"
        :customRow="isSort ? customRow : null"
      >
        <!-- 拖拽icon -->
        <template #sort>
          <HolderOutlined />
        </template>
      </a-table>
</template>

<script>
import { ref } from 'vue'
import { staffColumnsSort} from '../../columns'
import { HolderOutlined } from '@ant-design/icons-vue'
export default{
    components: {
        HolderOutlined
      },
    setup(){
        const sourceObj = ref({}) //源对象
        const targetObj = ref({}) //目标对象
        const dataSource = ref([])//列表数据
        const sortInfo = ref([])//整理后发给后台的数组
        const isSort = ref(true)//是否在排序状态下
        //移除拖拽样式方法
        const removeStyle = () => {
          document.getElementsByClassName('ant-table-tbody').forEach(parent => {
                parent.getElementsByTagName('tr').forEach(child => {
                  child.removeAttribute('style')
                })
              })
        }
        const customRow = (record, index) => {
          return {
            style: {
              cursor: 'grab'
            },
            // 鼠标移入
            onMouseenter: event => {
            // 兼容IE
            var ev = event || window.event
            ev.target.draggable = true
            },
            // 开始拖拽
            onDragstart: event => {
              // 兼容IE
              var ev = event || window.event
              // 阻止冒泡
              ev.stopPropagation()
              // 得到源目标数据
              sourceObj.value = record
            },
            // 拖动元素经过的元素
            onDragover: event => {
              // 兼容 IE
              var ev = event || window.event
              // 阻止默认行为
              ev.preventDefault()
              console.log('ant-table-tbody元素个数', document.getElementsByClassName('ant-table-tbody'))
              console.log('拖动元素经过的元素索引', index)
              console.log(
            '表格子元素',
                document.getElementsByClassName('ant-table-tbody')[0].getElementsByTagName('tr')[index]
              )

               //表格右侧操作栏使用了fixed固定定位,因此ant-table-tbody有两个
          document.getElementsByClassName('ant-table-tbody').forEach(parent => {
            parent.getElementsByTagName('tr').forEach((item, i) => {
              if (i === index) {
                item.style.borderBottom = '2px solid #1677ff'
              } else {
                item.removeAttribute('style')
              }
            })
          })
        },
        // 鼠标松开
        onDrop: event => {
          // 兼容IE
          var ev = event || window.event
          // 阻止冒泡
          ev.stopPropagation()
          // 得到目标数据
          targetObj.value = record
          console.log('源数据', sourceObj.value)
          console.log('目标数据', targetObj.value)

          const newArr = dataSource.value

          const source = newArr.findIndex(item => item.staffId ==sourceObj.value.staffId)

          const target = newArr.findIndex(item => item.staffId ==targetObj.value.staffId)

          newArr.splice(source, 1)
          newArr.splice(target, 0, sourceObj.value)

          sortInfo.value = []
          newArr.forEach((item, index) => {
            sortInfo.value.push({
              staffId: item.staffId,
              sortIndex: index
            })
          })
          //松开鼠标后,清除底部拖拽样式
          removeStyle()
        },
        //鼠标移出
        onMouseleave: event => {
          // 兼容IE
          var ev = event || window.event
          //鼠标移出拖拽范围禁止拖拽并清除拖拽效果
          ev.target.draggable = false
          removeStyle()
         
        }
      }
    } 

    return {
        sourceObj, 
        targetObj,
        dataSource,
        sortInfo,
        removeStyle,
        customRow,
        isSort  
        }
    }
}
</script>

//columns.js
export const staffColumnsSort = [
  {
    title: '',
    dataIndex: 'sort',
    key: 'sort',
    align: 'left',
    width: 92,
    slots: { customRender: 'sort' }
  },
  {
    title: '序号',
    dataIndex: 'id1',
    key: 'id1',
    align: 'left',
    width: 117,
    slots: { customRender: 'id1' }
  },
  {
    title: '姓名',
    dataIndex: 'staffName',
    key: 'staffName',
    align: 'left',
    slots: { customRender: 'staffName' },
    ellipsis: true,
    width: 225
  },
  {
    title: '账号',
    dataIndex: 'mobile',
    key: 'mobile',
    align: 'left',
    ellipsis: true,
    slots: { customRender: 'mobile' },
    width: 174
  },
  {
    title: '所属组织',
    dataIndex: 'departmentName',
    key: 'departmentName',
    align: 'left',
    ellipsis: true,
    slots: { customRender: 'departmentName' },
    width: 172
  },
  {
    title: '指纹录入',
    dataIndex: 'fingerprintEntry',
    key: 'fingerprintEntry',
    align: 'left',
    width: 144,
    ellipsis: true,
    slots: { customRender: 'fingerprintEntry' }
  },
  {
    title: '操作',
    dataIndex: 'action',
    key: 'action',
    align: 'left',
    slots: { customRender: 'action' },
    fixed: 'right',
    width: 124
  }
]

实现两个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> ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值