使用cdkDragDrop跨列表拖拽元素时如何避免生成多余索引
Angular CDK 跨列表拖放索引错乱修复方案

使用cdkDragDrop实现行数据跨列表移动时,同列表内排序正常,跨列表移动会生成多余无效新索引,可按以下步骤修复:
基础配置检查
首先确保模板层的拖放绑定配置正确,单向关联、漏绑数据源都会导致索引计算异常:
- 两个拖放容器必须双向配置
cdkDropListConnectedTo关联,不能只写单向引用 - 每个拖放容器必须通过
cdkDropListData绑定自身对应的独立数据数组,禁止两个容器共用同一个数组引用 - 所有可拖放行必须添加
cdkDrag指令,不要嵌套在其他非拖放元素内
参考正确模板写法:
<!-- 源列表容器 --> <div cdkDropList #sourceList="cdkDropList" [cdkDropListData]="sourceListData" [cdkDropListConnectedTo]="[targetList]" (cdkDropListDropped)="onListDrop($event)" > <div *ngFor="let row of sourceListData" cdkDrag> {{ row.label }} </div> </div> <!-- 目标列表容器 --> <div cdkDropList #targetList="cdkDropList" [cdkDropListData]="targetListData" [cdkDropListConnectedTo]="[sourceList]" (cdkDropListDropped)="onListDrop($event)" > <div *ngFor="let row of targetListData" cdkDrag> {{ row.label }} </div> </div>
正确的拖放回调逻辑
不要手动写splice操作数组,直接用CDK内置的数组操作方法处理,避免索引计算错误,这是出现多余索引的最常见原因:
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop'; onListDrop(event: CdkDragDrop<any[]>) { if (event.previousContainer === event.container) { // 同列表内排序,直接移动位置 moveItemInArray( event.container.data, event.previousIndex, event.currentIndex ); } else { // 跨列表移动,直接转移数据项 transferArrayItem( event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex ); } }
常见踩坑点
- 不要在拖放回调里手动给移动的数据项添加/修改索引、id类字段,内置方法会自动处理数组位置,手动修改会导致索引重复生成
- 如果*ngFor用了
trackBy优化,必须用数据项的唯一标识作为trackBy的返回值,禁止返回遍历index,否则跨列表时index变化会触发错误的DOM重建,出现多余行 - 不要在拖放事件触发时额外调用数组的接口刷新、重新赋值逻辑,等拖放完成后再同步数据即可
内容的提问来源于stack exchange,提问作者Ashish Rana
相关产品推荐
相关产品推荐

