在复杂板(矩阵)上拖放 Angular [英] Drag and Drop in Angular on complex board (matrix)

查看:18
本文介绍了在复杂板(矩阵)上拖放 Angular的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

这是 stackblitz 示例的链接:https://stackblitz.com/edit/角度-pp24ad

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

解决方案

您需要定义两个cdkDropList".一个 cdkDropList 它不是一个列表,在你的情况下,你可以有一个简单的 div 用于可用船只",以及一个样式为 position:relative 的 div,因为你想将ships"放在绝对位置.

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

可用船是

<ng-container *ngFor="让船的船"><div cdkDrag [style.size]="50*ship.size+'px'"><app-ship [name]="ship.name" [size]="ship.size"></app-ship><div *cdkDragPlaceholder></div>

</ng-容器>

而板"是

<ng-container *ngFor="let ship of shipInBoard"><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>

</ng-容器><!---这只是为了画板--><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"(鼠标悬停)="位置=bt.getBoundingClientRect()">

  1. 在板"中,我们使用 [style.top] 和 [style.left] 放置船"
  2. 我们已经定义了 [cdkDropListConnectedTo]="[cdkBoard]" 和[cdkDropListConnectedTo]="[cdkShips]"
  3. 我们有两个数组——它们是将被交换的数据:船舶和船舶InBoard

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

 drop(event: CdkDragDrop) {event.previousContainer.data[event.previousIndex].top=this.position?this.position.y-this.boardElement.nativeElement.getBoundingClientRect().y:0event.previousContainer.data[event.previousIndex].left=this.position?this.position.x-this.boardElement.nativeElement.getBoundingClientRect().x:0if (event.previousContainer === event.container) {moveItemInArray(event.container.data,event.previousIndex,事件.currentIndex);} 别的 {传输数组项(event.previousContainer.data,event.container.data,event.previousIndex,事件.currentIndex);}}

我制作了一个傻瓜"应用程序

<div class="ship-box" [style.width]="52*size+'px'" >{{姓名}}<div class="ship-drop-wrapper"><div *ngFor="let i of [0,1,2,3,4].slice(0,size)" class="ship-box-cell"(鼠标悬停)="index=i">

您可以看到 stackblitz

注意:您会注意到,当您将一艘船拖上船时,它会在您预期的上方排成一排.这是因为可用船"改变了高度

注意2:您早期需要为您的船"添加一个新属性旋转"以显示旋转位置 - 使用 [style.transform]='rotate(90deg)'-

So I want to make my version of the Battleships game in Angular and to do that I need a 10x10 matrix in which I can drag and drop the ships ( if you played the game you know what I am talking about ) and I'm using the Angular Cdk but I cannot make it work at all.

What I have tried so far is make a table out of divs, ships elements aside and drag and drop them on the board but I can't connect the two arrays because the array of ships is not nested and the board is.

Edit: Here is the link to the stackblitz example : https://stackblitz.com/edit/angular-pp24ad

It is noticeable that the matrix is filled with IBoxes which will help later during the game implementation. I am not sure if I have to change the data structure of the ships. For example to be another matrix from which I take the ships and transfer to the board but still, I can't figure out the dragging. I am still not sure that this is the best way to solve this problem so I am willing to change the way to solve the problem.

解决方案

You need has defined two "cdkDropList". A cdkDropList it's not necesary a list, in your case you can has a simple div for the "Available ships", and a div with style position:relative because you want to place the "ships" in a position absolute.

As idea, the data to pass between cdkDropList are object with name, size, top and left, so (imagine you has a "ship-component"). Remember, Angular work relations the model (variables in ts) and the view (how we show this variables). So the idea is has two arrays and pass elements from one to another

The Availables ships is

<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>

And the "board" is

<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>

See

  1. in the "board" we place the "ships" using [style.top] and [style.left]
  2. We has defined [cdkDropListConnectedTo]="[cdkBoard]" and [cdkDropListConnectedTo]="[cdkShips]"
  3. We has two arrays -that are the data that will be interchanged: ships and shipsInBoard

The drop event is who give value to top and left and after, interchange the elements in the arrays

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

I make a "fool" app-ship like

<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>

You can see stackblitz

NOTE: You'll note that when you drag a ship to board, it is place in a row above you expect. It's because the "available ships" change the heigth

NOTE2: you early need add a new property "rotate" to your "ships" to show in rotate position -use [style.transform]='rotate(90deg)'-

这篇关于在复杂板(矩阵)上拖放 Angular的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆