如何在Angular中实现元素的水平与垂直双向拖拽?
解决Angular CDK Drag Drop流式布局下的自由拖拽问题
要实现元素换行时同时支持水平和垂直方向的拖拽排序,你需要结合CSS流式布局和自定义CDK拖拽排序逻辑,具体步骤如下:
1. 调整HTML结构
移除cdkDropListOrientation属性,添加自定义排序函数绑定:
<div class="list" cdkDropList #todoList="cdkDropList" [cdkDropListData]="completed" [cdkDropListConnectedTo]="[doneList]" [cdkDropListSortingFn]="customSortingFn" (cdkDropListDropped)="onDrop($event)"> <ng-container *ngFor="let option of completed; let i = index"> <div class="mat-card" cdkDrag> <p>{{option.name}}</p> </div> </ng-container> </div>
注意:你的原代码中
*ngFor遍历的是options数组,但定义的数据源是completed,这里需要修正为completed。
2. 设置CSS流式布局
给列表容器添加样式,让元素自动换行排列:
.list { display: flex; flex-wrap: wrap; gap: 16px; /* 元素间距 */ padding: 16px; } .mat-card { padding: 12px 24px; background: #fff; border-radius: 4px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); min-width: 120px; }
3. 实现自定义排序函数
在组件TS文件中添加customSortingFn,根据拖拽元素的坐标计算正确的插入位置:
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop'; // ... completed = [ { name: 'HTML' }, { name: 'CSS' }, { name: 'Angular' }, { name: 'React' }, { name: 'Vue' } ]; customSortingFn = (a: CdkDrag, b: CdkDrag) => { const aRect = a.element.nativeElement.getBoundingClientRect(); const bRect = b.element.nativeElement.getBoundingClientRect(); // 先比较垂直位置(y轴),再比较水平位置(x轴) if (aRect.y !== bRect.y) { return aRect.y - bRect.y; } return aRect.x - bRect.x; }; onDrop(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 ); } }
原理说明
- 移除
cdkDropListOrientation后,CDK默认使用垂直排序逻辑,但我们通过CSS让元素横向流式排列。 - 自定义排序函数
customSortingFn会同时参考元素的垂直(y轴)和水平(x轴)位置,确保拖拽时插入到正确的位置,适配换行后的布局。 - 流式布局下元素会自动换行,拖拽时CDK会根据排序函数的结果更新数组顺序,从而同步DOM的排列。
内容的提问来源于stack exchange,提问作者Vivek Saha
相关产品推荐
相关产品推荐

