Angular CDK拖放:不要移动源项目

30

我正在尝试实现一个编辑器,可以拖动一个项目并将其添加到主内容中,问题是当我从源项目容器中拖出时,源项目总是被销毁。

有没有办法强制源项目保持在原地,同时仍然能够拖放该项?基本上,我想要的是复制行为而不是移动行为。

我已经看到了其他与我想要实现的基本相同的问题,但是它们都没有真正帮助我,因为这些问题更多关于如何在技术上完成复制项目,而我想知道如何在UI中实现此行为,因为看到该项目消失非常令人困惑。


4个回答

28

替换

drop(event: CdkDragDrop<string[]>) {
  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
    );
  }
}

随着

drop(event: any) {
  if (event.previousContainer === event.container) {
    moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
  } else {
    copyArrayItem(
      event.previousContainer.data,
      event.container.data,
      event.previousIndex,
      event.currentIndex
    );
  }
}

6
感谢提供解决方案。然而,这种行为会导致列表样式问题,因为它看起来像是在复制操作中从列表中移除和添加元素,从而使列表波动起来。请参考此 StackBlitz 链接:https://stackblitz.com/edit/angular-g5uzys?file=app%2Fcdk-drag-drop-connected-sorting-example.ts - Himanshu
是的,我们甚至需要copyArrayItem吗?我已经通过在drop方法中不更新源列表来使其与相同的UX工作。同意,拖出的视觉样式是问题所在。 - Ben Racicot

6

导入 import {copyArrayItem} from '@angular/cdk/drag-drop';

并且

transferArrayItem 替换为 copyArrayItem


4
以上所有解决方案都很好,但是存在一个问题:克隆在元素投放后发生,因此我进行了git转换并找到了以下解决方案。
样式:
.drag-container {
    width: 400px;
    max-width: 100%;
    margin: 0 25px 25px 0;
    display: inline-block;
    vertical-align: top;
}

.drag-list {
    border: solid 1px #ccc;
    min-height: 60px;
    background: white;
    border-radius: 4px;
    overflow: hidden;
    display: block;
}

.drag-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);
}

.cdk-drag-placeholder {
    opacity: 0;
}

.cdk-drag-animating {
    transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

.drag-box:last-child {
    border: none;
}

.drag-list.cdk-drop-list-dragging .drag-box:not(.cdk-drag-placeholder) {
    transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

类型Script

menu: any = [
    { title: 'pork', price: 12, id: 1 },
    { title: 'duck', price: 12, id: 2 },
    { title: 'chicken', price: 12, id: 3 },
    { title: 'beef', price: 12, id: 4 },
    { title: 'soup', price: 12, id: 5 },
  ];

  table: any = [];



  drop(event: any) {
    if (event.previousContainer !== event.container) {
      copyArrayItem(
        event.previousContainer.data,
        event.container.data,
        event.previousIndex,
        event.currentIndex
      );
    } else {
      moveItemInArray(
        event.container.data,
        event.previousIndex,
        event.currentIndex
      );
    }
    if (event.previousContainer.data) {
      this.menu = this.menu.filter((f: any) => !f.temp);
    }
  }



  exited(event: any) {
    const currentIdx = event.container.data.findIndex(
      (f: any) => f.id === event.item.data.id
    );
    this.menu.splice(currentIdx + 1, 0, {
      ...event.item.data,
      temp: true,
    });
  }
  entered() {
    this.menu = this.menu.filter((f: any) => !f.temp);
  }

HTML

<div cdkDropListGroup>
            <div class="drag-container">
                <h2>To do</h2>
                <div class="drag-list" cdkDropList #menuList="cdkDropList" [cdkDropListData]="menu" cdkDropListSortingDisabled [cdkDropListConnectedTo]="[tableList]" (cdkDropListDropped)="drop($event)" (cdkDropListExited)="exited($event)" (cdkDropListEntered)="entered()">
                    <div class="drag-box" *ngFor="let item of menu" cdkDrag [cdkDragData]="item">{{item.title}}</div>
                </div>
            </div>
            <div class="drag-container">
                <h2>Done</h2>
                <div class="drag-list" cdkDropList #tableList="cdkDropList" [cdkDropListData]="table" (cdkDropListDropped)="drop($event)">
                    <div class="drag-box" *ngFor="let item of table; let idx = index" cdkDrag>{{item.title}}</div>
                </div>
            </div>
</div>

来源1:StackBlitz

来源2:GitHub


1
+1 这个解决方案更好地回答了原始问题。使用Exited和Entered事件可以使用户体验更加流畅。 - Emmanuel

0
你需要找到目标和源的位置,然后复制数值。 情况1:从一个可拖动列表复制到另一个可拖动列表
   drop(event: any) {
        if (event.previousContainer === event.container) {
              moveItemInArray(
                event.container.data,
                event.previousIndex,
                event.currentIndex
              );
            } else {

              const prev_idx = event.previousIndex;
              const curr_id = event.currentIndex;
              // Copy the data.
              event.container.data[curr_id] = event.previousContainer.data[prev_idx];
        
            }
          }
    }

案例2:将列表中的数据复制到特定变量

drop(event: any) {
          // Copy the data to my-variable
                  const prev_idx = event.previousIndex;    
                  this.my-variable = event.previousContainer.data[prev_idx];
            
                }
              }
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接