问题
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.
回答1:
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
- in the "board" we place the "ships" using [style.top] and [style.left]
- We has defined [cdkDropListConnectedTo]="[cdkBoard]" and [cdkDropListConnectedTo]="[cdkShips]"
- 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)'-
来源:https://stackoverflow.com/questions/59916765/drag-and-drop-in-angular-on-complex-board-matrix