项目背景 : react + ant
单纯实现拖拽确实不难 , 我的需求是根据后台接口返回 , 生成对应的父子表格 , 并只可以拖拽子的位置 , 如图
后台返回的数据结构 (pid为0说明是父 , 子的pid等于父的id , 说明是父的子)
1 , 我先转成了树形结构且自己加上了key (注意 : key一定得是唯一的 , 否则会出现第一列数据拖拽不动 , 其他列数据可以拖拽的bug)
2 , 生成对应的父子表格 , 父要有对应的子 , 如图
3 , 更改onDragEnd的逻辑 , 实现效果
首先用.findIndex+.some来寻找当前子所属的父元素 , 然后再在父元素中用arrayMove将子调整顺序 , 最后创建一个新的副本仅仅更新当前父元素的子(注意 : 很关键 , 否则数据不更新) , 实现效果
否则就会如下图 , 有拖拽无更新 (图不太清晰 , 但"三里屯一直最上方")
整体代码
javascript
// 第一步的步骤 , 主要是生成我需要的树形结构和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>
)
})}