Angular拖拽复制:实现拖拽时不临时移除原容器元素
Angular CDK拖拽复制时保留原容器元素的实现方案
要实现拖拽复制时原容器元素不被临时移除,核心是把默认的"移动"逻辑改成"复制"逻辑,同时调整拖拽过程中的视觉表现,避免原元素被占位符替换而消失。以下是基于你提供的测试代码的具体修改步骤:
1. 修正HTML结构与事件绑定
- 修正
*ngFor的变量名(避免和数组名冲突) - 给
cdkDrag添加拖拽开始(cdkDragStarted)和拖拽结束(cdkDragStopped)事件,用来记录拖拽元素和恢复样式
修改后的HTML:
<div class="container"> <h2>Movies</h2> <div cdkDropList #moviesList="cdkDropList" [cdkDropListData]="MoviesList" [cdkDropListConnectedTo]="[doneMovieList]" class="movie-list" (cdkDropListDropped)="onDrop($event)"> <div class="movie-block" *ngFor="let movie of MoviesList" cdkDrag (cdkDragStarted)="onDragStarted($event, movie)" (cdkDragStopped)="onDragStopped($event)"> {{movie}} </div> </div> </div> <div class="container"> <h2>Movies Watched</h2> <div cdkDropList #doneMovieList="cdkDropList" [cdkDropListData]="MoviesWatched" [cdkDropListConnectedTo]="[moviesList]" class="movie-list" (cdkDropListDropped)="onDrop($event)"> <div class="movie-block" *ngFor="let movie of MoviesWatched" cdkDrag>{{movie}}</div> </div> </div>
2. 修改TS逻辑,实现复制而非转移
- 添加变量记录当前拖拽的元素
- 在
onDrop里把transferArrayItem换成复制操作(只添加到目标容器,不删除原容器元素) - 拖拽开始/结束时维护原元素的显示状态
修改后的TS:
import { Component } from '@angular/core'; import { CdkDragDrop, CdkDragStart, CdkDragEnd, moveItemInArray } from '@angular/cdk/drag-drop'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { MoviesList: any = [ 'The Far Side of the World', 'Morituri', 'Napoleon Dynamite', 'Pulp Fiction', 'Blade Runner', 'Cool Hand Luke', 'Heat', 'Juice' ]; MoviesWatched: any = []; draggedMovie: any; onDragStarted(event: CdkDragStart, movie: any) { this.draggedMovie = movie; // 确保原元素在拖拽过程中保持可见 event.source.element.nativeElement.style.opacity = '1'; } onDragStopped(event: CdkDragEnd) { this.draggedMovie = null; // 恢复原元素默认样式 event.source.element.nativeElement.style.opacity = ''; } onDrop(event: CdkDragDrop<any[]>) { if (event.previousContainer === event.container) { // 同容器内拖拽仍保持排序功能 moveItemInArray(event.container.data, event.previousIndex, event.currentIndex); } else { // 跨容器时执行复制操作,而非转移 if (this.draggedMovie) { event.container.data.splice(event.currentIndex, 0, this.draggedMovie); } } } }
3. 调整CSS,隐藏占位符避免原位置空出
默认的cdk-drag-placeholder会替换原元素并设为透明,导致原容器出现空白,直接隐藏占位符即可:
.wrapper { margin: 25px auto; max-width: 600px; text-align: center; padding: 0 20px; } .container { width: 45%; margin: 0 25px 25px 0; display: inline-block; vertical-align: top; } .movie-list { width: 80%; border: solid 1px #ccc; min-height: 60px; display: inline-block; background: white; border-radius: 4px; overflow: hidden; margin-top: 25px; } .movie-block { 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); } /* 修改占位符样式,直接隐藏 */ .cdk-drag-placeholder { display: none; } .cdk-drag-animating { transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); } .movie-block:last-child { border: none; } .movie-list.cdk-drop-list-dragging .movie-block:not(.cdk-drag-placeholder) { transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); }
核心原理说明
- 避免原元素移除:通过隐藏
cdk-drag-placeholder,阻止原元素被占位符替换,同时在拖拽开始时强制原元素保持可见 - 复制逻辑替代转移:放弃使用
transferArrayItem(该方法会删除原数组元素),改为直接将拖拽元素插入目标数组 - 状态维护:通过
cdkDragStarted和cdkDragStopped记录拖拽元素并恢复样式,确保交互过程的一致性
内容的提问来源于stack exchange,提问作者Nakul
相关产品推荐
相关产品推荐

