首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用cdkDropList自由拖动

用cdkDropList自由拖动
EN

Stack Overflow用户
提问于 2021-11-11 17:21:04
回答 1查看 109关注 0票数 0

我正在进行一个项目,在这个项目中,我需要实现某种类型的拖放区域,您可以从列表中拖动元素,然后将它们放到可以自由拖动的区域中。我还想为区域使用cdkDropList,因为它提供了连接列表的所有工具。我使用这个例子作为实现的参考,但我无法使它正常工作。

当我在区域中放置一个项目时,它不会掉到光标所在的位置,它只会转到我的区域的左上角,就像在列表中一样。

当我在区域中拖动一个项目时,它会正确地拖到我想要它被丢弃的地方,或者在下降点附近被拖放,或者回到左上角。

这里是我的cdkDrag元素,它不同于上面链接的示例,因为我绝对需要它在它自己的组件中(我希望在将来对它应用一些逻辑),但它本质上是相同的概念( cdkDropList div中的cdkDrag div)。我设法使用输出将所有需要的事件路由到父元素(区域)。

代码语言:javascript
复制
<div class="element-box"
     cdkDrag
     cdkDragBoundary={{boundary_name}}
     (cdkDragDropped)="dragDroppedEventToParent($event)"
     (cdkDragStarted)="dragStartedEventToParent($event)"
     (cdkDragMoved)="dragMovedEventToParent($event)">
    {{object_name}}
    <div *cdkDragPlaceholder class="field-placeholder"></div>
</div>

下面是,用于拖动元素的逻辑

代码语言:javascript
复制
export class ElementBoxComponent implements OnInit {

  @Input () object_name: string;
  @Input () boundary_name: string;
  @Input () itemSelf: any;

  @Output () dragMovedEvent = new EventEmitter<CdkDragMove>();
  @Output () dragStartedEvent = new EventEmitter<CdkDragStart>();
  @Output () dragDroppedEvent = new EventEmitter<any>();

  constructor() {}

  ngOnInit(): void {
  }

  dragMovedEventToParent(event: CdkDragMove) {
    this.dragMovedEvent.emit(event);
  }

  dragStartedEventToParent(event: CdkDragStart){
    this.dragStartedEvent.emit(event);
  }

  dragDroppedEventToParent(event: CdkDragEnd){
    this.dragDroppedEvent.emit({event, "self": this.itemSelf});
  }
}

下面是我的拖放区域元素,其中我呈现了拖放元素(您可以看到我将输出路由到区域逻辑中的方法):

代码语言:javascript
复制
<div class="drop-container"
      #cdkBoard
      cdkDropList
      [id]="'cdkBoard'"
      [cdkDropListData]="itemsInBoard"
      [cdkDropListConnectedTo]="connectedTo"
      cdkDropListSortingDisabled="true"
      (cdkDropListDropped)="itemDropped($event)">
  <app-element-box *ngFor="let item of itemsInBoard; let i=index" 
                  object_name="{{item.name}}" 
                  boundary_name=".drop-container" 
                  itemSelf="{{item}}"
                  style="position:absolute; z-index:i" 
                  [style.top]="item.top" 
                  [style.left]="item.left"
                  (dragMovedEvent)="elementIsMoving($event)"
                  (dragStartedEvent)="startedDragging($event)"
                  (dragDroppedEvent)="stoppedDragging($event)"></app-element-box>
  
  <svg-container class="bin-container" containerId="bin-image-container" *ngIf="_binVisible" height=40>
    <svg-image class="bin-icon" [imageUrl]="BIN_ICON_URL" height=40 width=40></svg-image>
  </svg-container>
</div>

下面是我的拖放区的TS文件中的相关方法:

代码语言:javascript
复制
itemDropped(event: CdkDragDrop<any[]>) {
    if (event.previousContainer === event.container) {
      moveItemInArray(this.itemsInBoard, event.previousIndex, event.currentIndex);
    } else {
      copyArrayItem(
        event.previousContainer.data,
        event.container.data,
        event.previousIndex,
        event.currentIndex
      )
    }
}

changePosition(event: CdkDragDrop<any>, field) {
    const rectZone = this.dropZone.nativeElement.getBoundingClientRect();
    const rectElement = event.item.element.nativeElement.getBoundingClientRect();
    const top = rectElement.top + event.distance.y - rectZone.top;
    const left = rectElement.left + event.distance.x - rectZone.left;

    const out = (top < 0) || (left < 0) || (top > (rectZone.height - rectElement.height)) || (left > (rectZone.width - rectElement.width));
    if (!out) {
      event.item.element.nativeElement.style.top = top + 'px';
      event.item.element.nativeElement.style.left = left + 'px';
    } else {
      this.itemsInBoard = this.itemsInBoard.filter((x) => x != event.item);
    }
}

同样,惟一的区别是,我的元素被封装在它们自己的组件中,并且我访问组件的顶部和左边样式元素的方式是不同的(示例中的代码没有工作)。我知道问题在于计算顶部变量和左变量的方法,但我已经坚持了一个星期了,似乎找不到它的问题所在。

这是一个短演示视频,如果您想更好地可视化我正在谈论的东西。

有人知道这是怎么回事吗?我愿意听取任何建议,谢谢:)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-13 10:51:19

没有乱七八糟的闪电战很难知道出了什么问题

这一堆闪电战中,我做了两个ckd列表

一个cdkDropList (todoList)是典型的“列表”,另一个是dropZone (doneList)。我的元素在路上

代码语言:javascript
复制
{label:string,x:number,y:number,'z-index':number}

cdkDrag中的dropZone阻碍了

代码语言:javascript
复制
<div cdkDrag class="item-box" 
        [style.top.px]="item.y" 
        [style.left.px]="item.x" 
        [style.z-index]="item['z-index']"
>

我选择todoList连接到dropZone,但是dropZone没有连接到任何东西。当我移动dropZone的元素时,如果它移开了这个元素,只需添加到列表中

我们需要把doneList作为ElementRef

代码语言:javascript
复制
  @ViewChild('doneList',{read:ElementRef,static:true}) dropZone:ElementRef;

以及相关函数

代码语言:javascript
复制
  drop(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,
      );
      event.item.data.y=(this._pointerPosition.y-this.dropZone.nativeElement.getBoundingClientRect().top)
      event.item.data.x=(this._pointerPosition.x-this.dropZone.nativeElement.getBoundingClientRect().left)
      this.changeZIndex(event.item.data)
    }
    this.posInside={source:null,x:0,y:0}
  }

  moved(event: CdkDragMove) {
    this._pointerPosition=event.pointerPosition;
  }

  changeZIndex(item:any)
  {
    this.done.forEach(x=>x['z-index']=(x==item?1:0))
  }
  changePosition(event:CdkDragDrop<any>,field)
  {
    const rectZone=this.dropZone.nativeElement.getBoundingClientRect()
    const rectElement=event.item.element.nativeElement.getBoundingClientRect()

    let y=+field.y+event.distance.y
    let x=+field.x+event.distance.x
    const out=y<0 || x<0 || (y>(rectZone.height-rectElement.height)) || (x>(rectZone.width-rectElement.width))
    
    if (!out)
    {
       field.y=y
       field.x=x
    }
    else{
      this.todo.push(field)
      this.done=this.done.filter(x=>x!=field)
    }
  }

喜欢.html

代码语言:javascript
复制
<div class="wrapper">
  <div
    cdkDropList
    #todoList="cdkDropList"
    [cdkDropListData]="todo"
    [cdkDropListConnectedTo]="[doneList]"
    class="example-list"
    (cdkDropListDropped)="drop($event)"
  >
    <div
      class="example-box"
      *ngFor="let item of todo"
      cdkDrag
      [cdkDragData]="item"
      (cdkDragMoved)="moved($event)"
    >
      {{ item.label }}
      <div *cdkDragPlaceholder class="field-placeholder"></div>
    </div>
  </div>
  <div
    cdkDropList
    #doneList="cdkDropList"
    [cdkDropListData]="done"
    class="drag-zone"
    cdkDropListSortingDisabled="true"
    (cdkDropListDropped)="drop($event)"
  >
    <ng-container *ngFor="let item of done">
      <div
        cdkDrag
        class="item-box"
        [style.top.px]="item.y"
        [style.left.px]="item.x"
        [style.z-index]="item['z-index']"
        (cdkDragStarted)="changeZIndex(item)"
        (cdkDragDropped)="changePosition($event, item)"
      >
        {{ item.label }}
        <div *cdkDragPlaceholder class="field-placeholder"></div>
      </div>
    </ng-container>
  </div>
</div>
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69932412

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档