react 表格实现拖拽功能

项目背景 : react + ant

单纯实现拖拽确实不难 , 我的需求是根据后台接口返回 , 生成对应的父子表格 , 并只可以拖拽子的位置 , 如图



后台返回的数据结构 (pid为0说明是父 , 子的pid等于父的id , 说明是父的子)


1 , 我先转成了树形结构且自己加上了key (注意 : key一定得是唯一的 , 否则会出现第一列数据拖拽不动 , 其他列数据可以拖拽的bug)


2 , 生成对应的父子表格 , 父要有对应的子 , 如图


3 , 更改onDragEnd的逻辑 , 实现效果
首先用.findIndex+.some来寻找当前子所属的父元素 , 然后再在父元素中用arrayMove将子调整顺序 , 最后创建一个新的副本仅仅更新当前父元素的子(注意 : 很关键 , 否则数据不更新) , 实现效果

否则就会如下图 , 有拖拽无更新 (图不太清晰 , 但"三里屯一直最上方")


特别注意 : 会出现第一行的拖拽失败 , 原因(当key是0时则不能拖拽 , 可以把data中的key赋值为id或者key+1 )



整体代码 

 

// 第一步的步骤 , 主要是生成我需要的树形结构和key , key很关键 , 必须唯一 !!!
const res = await getList()
    console.log('res', res)

    const parentRes = res.filter(item => item.parentId == 0)

    const parentRes1 = [
      ...new Map(parentRes.map(item => [item.locationId, item])).values()
    ] //拿到去重后的parentId为0且locationId不同的数据

    const parentRes2 = parentRes1.map((item, index) => ({
      ...item, // 保留原有属性
      children: [],
      key: item.locationId
    }))

    const sonRes = res.filter(item => item.parentId !== 0)
    const sonRes1 = sonRes.map((item, index) => ({
      ...item, // 保留原有属性

      key: item.locationId
    }))

    setSonData(sonRes1)

    //用俩个for循环遍历将sonRes根据parentId插入到对应的父节点children中
    for (let i = 0; i < sonRes1.length; i++) {
      for (let j = 0; j < parentRes2.length; j++) {
        if (sonRes1[i].parentId === parentRes2[j].locationId) {
          parentRes2[j].children.push(sonRes1[i])
        }
      }
    }

    //俩个for循环才能让children里的locationName也换成place
    for (let i = 0; i < parentRes2.length; i++) {
      parentRes2[i].place = parentRes2[i].locationName
      delete parentRes2[i].locationName
      for (let j = 0; j < parentRes2[i].children.length; j++) {
        parentRes2[i].children[j].place = parentRes2[i].children[j].locationName
        delete parentRes2[i].children[j].locationName
      }
    }

    console.log('data', parentRes2)

    setData(parentRes2)



// 第三步的逻辑
const onDragEnd = ({ active, over }) => {
    console.log('active', active)

    console.log('over', over)
    if (active.id !== over?.id) {
      setData(prevData => {
        // 寻找当前拖拽元素所属的父元素
        const parentIndex = prevData.findIndex(parent =>
          parent.children.some(child => child.key === active.id)
        )
        if (parentIndex !== -1) {
          const parent = prevData[parentIndex]

          // 在父元素的children中调整顺序
          const activeChildIndex = parent.children.findIndex(
            child => child.key === active.id
          )
          const overChildIndex = parent.children.findIndex(
            child => child.key === over?.id
          )
          if (activeChildIndex > -1 && overChildIndex > -1) {
            const newChildren = arrayMove(
              parent.children,
              activeChildIndex,
              overChildIndex
            )
            // 创建一个新的prevData副本,仅更新当前父元素的children
            const newData = [...prevData]
            newData[parentIndex] = { ...parent, children: newChildren }
   

            // 收集newData中所有对象的id和sort值传递给后端
            const updatedItems = newChildren.map(item => ({
              id: item.locationId,
              sort: item.sort
            }))

            getSortMethod({ sorts: updatedItems }) // 传递给后端

            return newData
          }
        }

        console.log('prevData', prevData)

        return prevData // 如果没有找到或无法处理,返回原数据
      })
    }
  }





// 这里是第二步的内容 , 生成对应的父子表格
{data.map((item, index) => {    

   return (
                <div key={item.key}>
                  <DndContext
                    modifiers={[restrictToVerticalAxis]}
                    onDragEnd={onDragEnd}
                  >
                    <SortableContext
                      items={SonData.map(i => i?.key)}
                      strategy={verticalListSortingStrategy}
                    >
                      <Table
                        rowKey='key'
                        columns={updatedColumns} // 确保此处的columns是根据item动态调整后的
                        dataSource={item.children} // 此处确保使用当前item的children作为dataSource
                        pagination={false}
                        components={{
                          body: {
                            row: Row1
                          }
                        }}
                        isSelectAll={isSelectAll}
                        rowSelection={{
                          ...rowSelection2,
                          selectedRowKeys: selectedRowKeys2,
                          checkStrictly
                        }}
                      />
                    </SortableContext>
                  </DndContext>
                </div>
              )
            })}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值