如何实现Angular Material cdkDropList元素拖拽远离后脱离原容器
实现方案
该效果可以实现,无需依赖cdkDropList的多列表关联逻辑,核心是通过拖拽事件判断位置阈值,结合CDK原生自由拖拽能力完成:
核心实现步骤
1. 绑定拖拽事件判断脱离阈值
在cdkDragReleased或cdkDropListDropped事件中,获取拖拽结束时的指针坐标,和原拖放列表的边界对比,超过自定义阈值则触发脱离逻辑,示例代码如下:
import { CdkDragRelease, CdkDrag } from '@angular/cdk/drag-drop'; // 原列表数据源 items = ['元素1', '元素2', '元素3', '元素4']; // 自由放置元素数据源 freeItems = []; // 自定义脱离阈值:距离原列表边界50px即判定为脱离 private readonly THRESHOLD = 50; @ViewChild('originDropList') originDropList: ElementRef; onDragReleased(event: CdkDragRelease) { const listRect = this.originDropList.nativeElement.getBoundingClientRect(); const dragPosition = event.source.getFreeDragPosition(); // 判断是否超出脱离阈值范围 const isOutOfList = dragPosition.x < listRect.left - this.THRESHOLD || dragPosition.x > listRect.right + this.THRESHOLD || dragPosition.y < listRect.top - this.THRESHOLD || dragPosition.y > listRect.bottom + this.THRESHOLD; if (isOutOfList) { // 从原列表移除对应元素 const dragItem = event.source.data; const itemIndex = this.items.findIndex(i => i === dragItem); if (itemIndex > -1) { this.items.splice(itemIndex, 1); } // 加入自由放置元素列表,记录当前位置 this.freeItems.push({ content: dragItem, x: dragPosition.x, y: dragPosition.y }); } }
2. 模板层分别渲染原列表和自由放置元素
单独渲染已经脱离原列表的元素,直接添加cdkDrag属性无需包裹在cdkDropList内,默认就支持松开后停在当前位置不会回弹:
<!-- 原拖放列表 --> <div cdkDropList #originDropList="cdkDropList" [cdkDropListData]="items" (cdkDragReleased)="onDragReleased($event)" > <div cdkDrag *ngFor="let item of items" [cdkDragData]="item"> {{ item }} </div> </div> <!-- 自由放置区域 --> <div class="free-drag-area"> <div cdkDrag *ngFor="let freeItem of freeItems" [style.left.px]="freeItem.x" [style.top.px]="freeItem.y" style="position: absolute;" > {{ freeItem.content }} </div> </div>
优化选项
- 若无需保留原列表的排序能力,可以直接给元素添加
[cdkDragReturnToOrigin]="false"属性,拖拽到任意位置松开都不会回弹到原列表,再配合事件逻辑处理原列表元素移除即可。 - 自由放置的元素可以按需添加边界限制,比如通过
cdkDragBoundary属性限定只能在指定区域内拖拽。
内容的提问来源于stack exchange,提问作者ebarooni
相关产品推荐
相关产品推荐

