为什么我拖到下拉列表中的元素在使用 Angular Material 时会丢失顶部和左侧 CSS 属性?

Why my dragged element into the drop-list is loosing top and left CSS properties, when using Angular Material?

在过去的 3 天里,我学习了 Angular Material 拖放,并尝试使用 Angular Material 将 objects/elements 的拖放添加到 10x10 矩阵中。

找到 and this stackblitz 后,我试图将其纳入我的需求和概念。我必须修复一些错误,更改样式、数组等。

Here is my stackblitz。我非常接近完成它,但是有两个错误我无法弄清楚如何修复它们,而且我在上面的示例中找不到任何解决方案:

  1. 在这个上我已经工作了大约 24 小时。将一艘船部署到板上并部署后,当您在板上移动同一艘船时,将它移动到不同的行和列时没有问题。但是当你将它移动到与之前相同的列时,app-ship元素(ShipComponent的选择器)丢失CSSleft 属性。当你将它移动到 同一行 时,它会失去 CSS top 属性,并且在视觉上被放置在矩阵的边缘,相同就像 left 道具一样。拖入同一列的示例: 我完全不知道为什么它会失去这些属性。

  2. 第二个错误,我还没有处理,但也许你现在会有一些想法,发生在你已经将 2 艘或更多船部署到游戏板时,一开始你是移动一艘船,然后移动另一艘船,而不是另一艘船将移动第一艘,第二艘将移动到左上角,缺少 lefttop CSS属性。

这两个问题很有可能相互关联。

component.ts:

import { Component, ElementRef, ViewChild } from "@angular/core";
import {
  CdkDragDrop,
  moveItemInArray,
  transferArrayItem,
} from "@angular/cdk/drag-drop";
import { ShipComponent } from "./ship.component";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
})

//https://stackblitz.com/edit/angular-salbpl?file=src%2Fapp%2Fapp.component.html
export class AppComponent {
  public list1: Array<ShipComponent>;
  public list2: Array<ShipComponent>;
  public boardP1: number[][];
  public position: any;

  constructor() {
    this.boardP1 = this.getEmptyBoard();
    this.list1 = this.createFleet();
    this.list2 = [];
  }

  @ViewChild("two", { read: ElementRef, static: false }) boardElement: any;
  @ViewChild("ships", { read: ElementRef, static: false }) shipsElement: any;

  onDrop(event: CdkDragDrop<Array<ShipComponent>>) {
    console.clear();
    console.log(this.position);
    event.previousContainer.data[event.previousIndex].top =
      this.position.y -
      this.boardElement.nativeElement.getBoundingClientRect().y;
    event.previousContainer.data[event.previousIndex].left =
      this.position.x -
      this.boardElement.nativeElement.getBoundingClientRect().x;

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

    console.log("t: " + event.container.data[event.previousIndex].top);
    console.log("l: " + event.container.data[event.previousIndex].left);
    console.log("s: " + event.container.data[event.previousIndex].size);
    if (this.shipsElement.nativeElement) {
      console.log("top: " + this.shipsElement.nativeElement.style.top);
      console.log("left: " + this.shipsElement.nativeElement.style.left);
    }
  }

  private createFleet(): Array<ShipComponent> {
    return [
      { size: 4, rotate: false, top: 0, left: 0 },
      { size: 3, rotate: false, top: 0, left: 0 },
      { size: 3, rotate: false, top: 0, left: 0 },
      { size: 2, rotate: false, top: 0, left: 0 },
      { size: 2, rotate: false, top: 0, left: 0 },
      { size: 2, rotate: false, top: 0, left: 0 },
      { size: 1, rotate: false, top: 0, left: 0 },
      { size: 1, rotate: false, top: 0, left: 0 },
      { size: 1, rotate: false, top: 0, left: 0 },
      { size: 1, rotate: false, top: 0, left: 0 },
    ];
  }

  private getEmptyBoard(): number[][] {
    return Array.from({ length: 10 }, () => Array(10).fill(0));
  }
}

component.html:

<div class="container">
  <div class="ships">
    <h2>Available ships: {{ this.list1.length }}</h2>
    <div
      class="droplist"
      cdkDropList
      #one="cdkDropList"
      [cdkDropListData]="list1"
      [cdkDropListConnectedTo]="[two]"
      (cdkDropListDropped)="onDrop($event)"
      cdkDropListSortingDisabled="true"
    >
      Next:

      <ng-container *ngIf="list1.length > 0">
        <div cdkDrag [style.size]="50 * list1[0].size + 'px'">
          <app-ship [size]="list1[0].size"></app-ship>
        </div>
      </ng-container>
    </div>
  </div>
</div>

<div class="example-boundary">
  <div
    class="droplist"
    cdkDropList
    #two="cdkDropList"
    [cdkDropListData]="list2"
    [cdkDropListConnectedTo]="[one]"
    (cdkDropListDropped)="onDrop($event)"
    cdkDropListSortingDisabled="true"
  >
    <ng-container *ngFor="let ship of list2">
      <app-ship
        #ships
        [size]="ship.size"
        cdkDrag
        [style.top.px]="ship.top"
        [style.left.px]="ship.left"
      >
      </app-ship>
    </ng-container>
    <div class="board">
      <div class="row" *ngFor="let row of boardP1">
        <div class="cell" *ngFor="let box of row" id="columns">
          <button
            #bt
            mat-button
            class="bt-cell"
            (mouseover)="position = bt.getBoundingClientRect()"
          ></button>
        </div>
      </div>
    </div>
  </div>
</div>

This mentioned example 在线工作,但在我的本地机器上无法正常工作,可能是因为 Angular 8 个版本,而我使用的是 10+。我也找不到修复错误的方法。我决定重新构建我的示例项目,并通过 Material 在我的组件中拖放 来更好地控制所做的事情。

最后,在工作解决方案中,我决定摆脱 CdkDragDrop 事件、moveItemInArraytransferArrayItem 并对数组和对象进行手动操作。现在我只使用:cdkDragcdkDragStartedcdkDragEndedcdkDragMoved 事件。

Here is version of my solution 修复了提到的错误。