在复杂板(矩阵)上以 Angular 拖放

Val*_*kov 0 drag-and-drop angular-material angular angular-cdk

所以我想用 Angular 制作我的战舰游戏版本,为此我需要一个 10x10 矩阵,我可以在其中拖放船只(如果你玩过游戏,你知道我在说什么)并且我正在使用Angular Cdk,但我根本无法让它工作。

到目前为止我所尝试的是用 div 制作一个表格,将元素放在一边并将它们拖放到板上,但我无法连接两个数组,因为船只数组不是嵌套的,而板是嵌套的。

编辑:这是 stackblitz 示例的链接:https ://stackblitz.com/edit/angular-pp24ad

值得注意的是,矩阵中充满了 IBox,这将有助于稍后的游戏实现。我不确定是否必须更改船舶的数据结构。例如,作为另一个矩阵,我从中获取船只并转移到棋盘上,但我仍然无法弄清楚拖动。我仍然不确定这是解决这个问题的最好方法,所以我愿意改变解决问题的方法。

Eli*_*seo 7

您需要定义两个“cdkDropList”。cdkDropList 不需要列表,在您的情况下,您可以为“可用船舶”设置一个简单的 div,并使用样式为position:relative 的 div,因为您希望将“船舶”放置在绝对位置。

作为想法,在 cdkDropList 之间传递的数据是具有名称、大小、顶部和左侧的对象,因此(假设您有一个“船舶组件”)。请记住,Angular 工作关系模型(ts 中的变量)和视图(我们如何显示这些变量)。所以这个想法是有两个数组并将元素从一个数组传递到另一个数组

可用船只是

<div cdkDropList #cdkShips=cdkDropList 
        [cdkDropListData]="ships" class="ship-list"
        [cdkDropListConnectedTo]="[cdkBoard]" 
        (cdkDropListDropped)="drop($event)" 
        cdkDropListSortingDisabled="true">

        <ng-container *ngFor="let ship of ships">
            <div cdkDrag [style.size]="50*ship.size+'px'">
                <app-ship [name]="ship.name" [size]="ship.size"></app-ship>
                <div *cdkDragPlaceholder></div>
            </div>
        </ng-container>
    </div>
Run Code Online (Sandbox Code Playgroud)

而“板”是

<div cdkDropList #cdkBoard=cdkDropList style="position:relative" 
     [cdkDropListData]="shipsInBoard" 
     [cdkDropListConnectedTo]="[cdkShips]"
     (cdkDropListDropped)="drop($event)" 
     cdkDropListSortingDisabled="true">

    <ng-container *ngFor="let ship of shipsInBoard">
        <div style="position:absolute" 
            [style.top]="ship.top+'px'" 
            [style.left]="ship.left+'px'" cdkDrag>
            <app-ship [name]="ship.name" [size]="ship.size"></app-ship>
            <div *cdkDragPlaceholder></div>
        </div>
    </ng-container>

    <!---this it's only to draw the board-->
    <div class="row" *ngFor="let row of board;let i=index">
        <div class="cell" *ngFor="let box of row;let j=index" id='columns'>
            <button #bt mat-button class="bt-cell" 
              (mouseover)="position=bt.getBoundingClientRect()">
            </button>
        </div>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

  1. 在“board”中,我们使用 [style.top] 和 [style.left] 放置“ships”
  2. 我们定义了 [cdkDropListConnectedTo]="[cdkBoard]" 和 [cdkDropListConnectedTo]="[cdkShips]"
  3. 我们有两个数组——即将交换的数据:ships 和shipsInBoard

drop事件是给top、left和after赋值,交换数组中的元素

  drop(event: CdkDragDrop<string[]>) {
      event.previousContainer.data[event.previousIndex].top=this.position?
            this.position.y-this.boardElement.nativeElement.getBoundingClientRect().y:
            0
      event.previousContainer.data[event.previousIndex].left=this.position?
        this.position.x-this.boardElement.nativeElement.getBoundingClientRect().x:
            0

    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
      );
    }
  }
Run Code Online (Sandbox Code Playgroud)

我做了一个“傻瓜”应用程序,就像

<div class="ship-box" [style.width]="52*size+'px'"  >
        {{name}}
   <div class="ship-drop-wrapper">
      <div *ngFor="let i of [0,1,2,3,4].slice(0,size)" class="ship-box-cell" 
        (mouseover)="index=i">
      </div>
   </div>
</div>
Run Code Online (Sandbox Code Playgroud)

你可以看到stackblitz

注意:您会注意到,当您将一艘船拖到船上时,它会放置在您预期上方的一行中。这是因为“可用船只”改变了高度

注意2:您早期需要向“ships”添加一个新属性“rotate”以显示旋转位置 -use [style.transform]='rotate(90deg)'-