You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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拖拽的动画定位逻辑冲突,导致第一个元素被错误移除。


解决方案

有两种可行的解决方式:

  1. 改用索引追踪:将@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>
  1. 使用唯一标识对象:将数组元素改为带唯一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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 16:42:07