如何在Angular CDK中实现拖拽图片的克隆、自动排列与重对齐?
问题描述
我正在开发Angular拖拽功能,需要实现以下需求:
- 拖拽图片时生成克隆副本
- 将图片放入指定容器后固定在该容器内
- 若放入错误容器,图片需返回原位置
- 支持同一容器放置多张图片,且自动依次排列
- 移除中间图片后,剩余图片自动重新对齐
请问如何通过Angular CDK实现这些功能?
现有代码
HTML
<div class="drop-container"> <div cdkDropList #doneList="cdkDropList" [cdkDropListData]="done" class="drop-list rec" (cdkDropListDropped)="drop($event)"> <div class="example-box" *ngFor="let item of done" cdkDrag><img [src]="item" /></div> </div> </div> <div class="drag-container"> <div cdkDropList [cdkDropListData]="todo" [cdkDropListConnectedTo]="[doneList]" [cdkDropListSortingDisabled]="true" class="drag-list" (cdkDropListEntered)="entered($event)" (cdkDropListExited)="exited($event)" [ngClass]="{'drag-stop': count === 1}"> <ng-container *ngFor="let item of todo"> <img [src]="item" cdkDrag [cdkDragData]="item" /> <div class="example-box" > <img [src]="item" *ngIf="transferringItem === item"/> </div> </ng-container> </div> </div>
TypeScript
import { Component } from "@angular/core"; import { CdkDragDrop, copyArrayItem, CdkDragExit, CdkDragEnter } from "@angular/cdk/drag-drop"; @Component({ selector: 'app-halsband', templateUrl: './halsband.component.html', styleUrl: './halsband.component.css' }) export class HalsbandComponent { todo:string[] = ['assets/Images/images/Tiobas_b3.png']; done: string[] = ['']; transferringItem: string = ''; count: number = 0; drop(event: CdkDragDrop<string[]>) { this.count++; if (event.previousContainer.id !== event.container.id) { copyArrayItem( event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex ); } this.transferringItem = ''; } entered(e: CdkDragEnter<any>) { this.transferringItem = ''; } exited(e: CdkDragExit<any>) { console.log(e.item.data); this.transferringItem = e.item.data; } }
CSS
.drop-container { display: flex; justify-content: center; width: 100%; } .drop-list { border: solid 1px #ccc; background: white; border-radius: 4px; overflow: hidden; display: flex; width: 15vw; height: 15vw; } .drag-container { display: flex; justify-content: center; width: 100%; margin-top:2vw; } .example-box { padding: 20px 10px; border-bottom: solid 1px #ccc; color: rgba(0, 0, 0, 0.87); display: flex; flex-direction: row; align-items: center; justify-content: space-between; box-sizing: border-box; cursor: move; background: white; font-size: 14px; } .cdk-drag-preview { box-sizing: border-box; border-radius: 4px; box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12); } .rec .cdk-drag-placeholder { opacity: 0; } .cdk-drag-animating { transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); } .example-box:last-child { border: none; } .example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) { transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); } .drag-stop { opacity: 0.3; pointer-events: none; }
解决方案与代码修改
以下是针对需求的具体实现调整:
1. 拖拽生成克隆副本
给拖拽图片添加[cdkDragCopy]="true"属性,Angular CDK会自动创建拖拽副本,原元素保留在初始容器。
2. 指定容器判断与返回原位置
给目标容器添加id="target-container",在drop事件中仅允许拖入该容器,其他容器不执行复制操作,CDK会自动将拖拽元素返回原位置。
3. 多张图片自动排列
修改目标容器的CSS,开启flex-wrap: wrap并设置间距,实现图片自动换行排列。
4. 移除图片后自动对齐
添加删除按钮,通过splice删除数组元素,*ngFor会自动重新渲染列表,剩余图片自动对齐。
修改后的完整代码
HTML
<div class="drop-container"> <div cdkDropList #doneList="cdkDropList" id="target-container" [cdkDropListData]="done" class="drop-list rec" (cdkDropListDropped)="drop($event)"> <div class="example-box" *ngFor="let item of done; let i = index" cdkDrag> <img [src]="item" /> <button (click)="removeItem(i)">删除</button> </div> </div> </div> <div class="drag-container"> <div cdkDropList [cdkDropListData]="todo" [cdkDropListConnectedTo]="[doneList]" [cdkDropListSortingDisabled]="true" class="drag-list"> <img [src]="item" *ngFor="let item of todo" cdkDrag [cdkDragData]="item" [cdkDragCopy]="true" /> </div> </div>
TypeScript
import { Component } from "@angular/core"; import { CdkDragDrop, copyArrayItem } from "@angular/cdk/drag-drop"; @Component({ selector: 'app-halsband', templateUrl: './halsband.component.html', styleUrl: './halsband.component.css' }) export class HalsbandComponent { todo:string[] = ['assets/Images/images/Tiobas_b3.png']; done: string[] = []; // 移除默认空字符串占位 drop(event: CdkDragDrop<string[]>) { // 仅允许拖入指定目标容器 if (event.container.id === 'target-container') { copyArrayItem( event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex ); } } removeItem(index: number) { this.done.splice(index, 1); } }
CSS
.drop-container { display: flex; justify-content: center; width: 100%; } .drop-list { border: solid 1px #ccc; background: white; border-radius: 4px; overflow: auto; display: flex; flex-wrap: wrap; /* 开启自动换行 */ gap: 10px; /* 图片间距 */ padding: 10px; width: 40vw; min-height: 15vw; } .drag-container { display: flex; justify-content: center; width: 100%; margin-top:2vw; } .example-box { padding: 5px; border: solid 1px #ccc; border-radius: 4px; display: flex; flex-direction: column; align-items: center; box-sizing: border-box; cursor: move; background: white; } .example-box img { width: 80px; height: 80px; object-fit: cover; } .cdk-drag-preview { box-sizing: border-box; border-radius: 4px; box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12); } .rec .cdk-drag-placeholder { opacity: 0; } .cdk-drag-animating { transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); }
内容的提问来源于stack exchange,提问作者Pykara_Developer
相关产品推荐
相关产品推荐

