Angular Material拖拽排序后首元素消失问题求助
问题:Angular CDK拖拽排序后首个元素消失
参照Angular Material拖拽排序示例实现单列表拖拽排序,但每次拖拽调整顺序后,列表第一个元素都会消失,代码与官网示例一致:
模板代码
<div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)"> @for (movie of movies; track movie) { <div class="example-box" cdkDrag>{{movie}}</div> } </div>
组件代码
import {Component} from '@angular/core'; import {CdkDragDrop, CdkDropList, CdkDrag, moveItemInArray} from '@angular/cdk/drag-drop'; @Component({ selector: 'cdk-drag-drop-sorting-example', templateUrl: 'cdk-drag-drop-sorting-example.html', styleUrls: ['cdk-drag-drop-sorting-example.css'], standalone: true, imports: [CdkDropList, CdkDrag], }) export class CdkDragDropSortingExample { movies = [ 'Episode I - The Phantom Menace', 'Episode II - Attack of the Clones', 'Episode III - Revenge of the Sith', 'Episode IV - A New Hope', 'Episode V - The Empire Strikes Back', 'Episode VI - Return of the Jedi', 'Episode VII - The Force Awakens', 'Episode VIII - The Last Jedi', 'Episode IX – The Rise of Skywalker', ]; drop(event: CdkDragDrop<string[]>) { moveItemInArray(this.movies, event.previousIndex, event.currentIndex); } }
原因分析
问题出在@for循环的track movie配置上。Angular新的@for指令追踪逻辑比旧版*ngFor更严格,直接用字符串作为追踪标识时,拖拽后数组顺序变化,Angular的DOM复用机制会与CDK拖拽的动画定位逻辑冲突,导致第一个元素被错误移除。
解决方案
有两种可行的解决方式:
- 改用索引追踪:将
@for循环的追踪表达式改为track $index,确保每个列表项能被唯一识别:
<div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)"> @for (movie of movies; track $index) { <div class="example-box" cdkDrag>{{movie}}</div> } </div>
- 使用唯一标识对象:将数组元素改为带唯一ID的对象,用ID作为追踪标识(更符合Angular最佳实践,适合复杂场景):
// 组件中修改movies数组结构 movies = [ {id: 1, title: 'Episode I - The Phantom Menace'}, {id: 2, title: 'Episode II - Attack of the Clones'}, {id: 3, title: 'Episode III - Revenge of the Sith'}, {id: 4, title: 'Episode IV - A New Hope'}, {id: 5, title: 'Episode V - The Empire Strikes Back'}, {id: 6, title: 'Episode VI - Return of the Jedi'}, {id: 7, title: 'Episode VII - The Force Awakens'}, {id: 8, title: 'Episode VIII - The Last Jedi'}, {id: 9, title: 'Episode IX – The Rise of Skywalker'}, ];
<!-- 模板中修改追踪和显示逻辑 --> <div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)"> @for (movie of movies; track movie.id) { <div class="example-box" cdkDrag>{{movie.title}}</div> } </div>
内容的提问来源于stack exchange,提问作者Marko
相关产品推荐
相关产品推荐

