使用 Angular 拖放图像图标
Drag and Drop image icons using Angular
我使用 angular 设计了一个网格。我将从图像列表中拖出一些图像并将它们放入网格图块中。下面附上设计图
这是我的打字稿代码
officeItems = [Image's URL];
drop(event: CdkDragDrop<string[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(
event.container.data,
event.previousIndex,
event.currentIndex
);
} else {
copyArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex
);
}
}
HTML代码
<div class="row">
<div class="col-10" cdkDropList #cellList="cdkDropList" [cdkDropListData]="cells" [cdkDropListConnectedTo]="[itemList]">
<mat-grid-list cols="10" >
<mat-grid-tile *ngFor="let cell of cells" [style.background]="cell.color">
<img *ngIf="cell.url" src="{{cell.url}}"/>
</mat-grid-tile>
</mat-grid-list>
</div>
<div class="col-2" cdkDropList #itemList="cdkDropList" [cdkDropListData]="officeItems" [cdkDropListConnectedTo]="[cellList]" (cdkDropListDropped)="drop($event)">
<pre *ngFor="let item of officeItems" cdkDrag><img src= "{{item}}" title="Sofa" style="margin-top: 10px;"/></pre>
</div>
</div>
ts文件中有两个数据数组
cells= [
{ id: 1, minDistanceToA: 0.0 },
{ id: 2, minDistanceToA: 1.0 },
{ id: 3, minDistanceToA: 2.0 },
{ id: 4, minDistanceToA: 3.0 },
{ id: 5, minDistanceToA: 4.0 }];
officeItems: any = ['../assets/images/sofa1.png', '../assets/images/chair.png'}];
我可以拖动图像但不能放下它们。当我尝试删除时,它再次替换为之前的 div
我试过使用您的代码,并在一天的前半天进行了处理。
我得出的结论是,结合 mat-grid 和 cdkDropList 是个坏主意。
不过,我可以告诉您的是,使用 copyArrayItem 并不能使您到达想要的位置。
改用这个:
onDrop(event: CdkDragDrop<cell[]>) {
if (!(event.previousContainer === event.container)){
event.container.data[event.currentIndex] =
event.previousContainer.data[event.previousIndex];
}
}
这将做什么:
容器:包含 cdkDragDrop 项目的数组
Index: 用于挑选单件商品
- 获取您正在将另一个项目拖入的项目(当前索引处的当前容器数组)
- 将其替换为您当前正在拖动的项目(上一个索引处的上一个容器数组)
我知道我迟到了,但是...
在“网格”中管理 cdk 拖放非常复杂,因为 material angular cdkDropList 考虑单维
想法总是一样的,而不是使用唯一的 cdkDropList,我们可以创建如此多的 cdkDropList 作为我们拥有的元素 - 在外面的情况下,网格。全部包含在 div 和 cdkDropListGroup
-
中
<div class="content" cdkDropListGroup>
<div #board class="board">
<mat-grid-list cols="5">
<mat-grid-tile *ngFor="let cell of cells; let i = index">
<div
class="cell"
cdkDropList
[cdkDropListData]="cell"
(cdkDropListDropped)="drop($event)"
[style.background]="i == indexOver ? 'red' : 'yellowgreen'"
(mouseover)="this.indexOver = i"
(mouseout)="indexOver = -1"
>
<div cdkDrag>
<img
*ngIf="cell.src"
[src]="cell.src"
width="100%"
/>
<span *ngIf="!cell.src"></span>
<div *cdkDragPlaceholder></div>
</div>
</div>
</mat-grid-tile>
</mat-grid-list>
</div>
<div
class="side"
cdkDropList
sortingDisabled="true"
[cdkDropListData]="icons"
(cdkDropListDropped)="drop($event)"
>
<div *ngFor="let icon of icons">
<div cdkDrag (mousedown)="calculeMargin($event)">
<img [src]="icon" />
<img
*cdkDragPreview
[src]="icon"
[ngStyle]="previewStyle ? previewStyle : null"
/>
<div *cdkDragPlaceholder></div>
</div>
</div>
</div>
</div>
我们的 mat-grid-tile 将是“cdkDrag”,这会根据 cell.src 的值显示 img 或 span。看到我们创建了一个“空”*cdkDragPlaceholder
在另一边,我们有一个典型的列表。我们转换 cdkDragPreview 使我们拖动元素时与我们的“tiles”大小相同(这是 (mousedown)="calculeMargin($event")
的目的
我使用相同的函数“drop”来控制所有的drop。为了检查我们是从“板”还是从“侧面”拖动,我使用了自己的“数据”。如果有一个 属性 "src" 是板上的一个项目,否则是侧面的一个项目。看到我们不使用“传输”或其他“奇怪的功能”,否则只需压入或更改数组的元素
indexOver:number=-1;
previewStyle: any = null;
@ViewChild(MatGridTile, { static: false, read: ElementRef }) model;
@ViewChild('board', { static: false,read:ElementRef })board:ElementRef;
icons = [
'https://picsum.photos/100/100?random=1',
'https://picsum.photos/100/100?random=2',
'https://picsum.photos/100/100?random=3',
];
cells = Array(25).fill(' ').map((_,index)=>({src:null,id:index}));
constructor() {}
ngOnInit() {
setTimeout(() => {
const rect = this.model.nativeElement.getBoundingClientRect();
this.previewStyle = {
width: rect.width + 'px',
height: rect.height + 'px',
};
});
}
calculeMargin(event: MouseEvent) {
const rect = this.model.nativeElement.getBoundingClientRect();
this.previewStyle = {
width: rect.width + 'px',
height: rect.height + 'px',
'margin-top': -event.offsetY + 'px',
'margin-left': -event.offsetX + 'px',
};
}
drop(event: CdkDragDrop<any>) {
if (event.previousContainer != event.container) {
if (event.container.data.src!==undefined)
{
if (event.previousContainer.data.src!=undefined)
{
event.container.data.src=event.previousContainer.data.src
event.previousContainer.data.src=null;
}
else
{
event.container.data.src=event.previousContainer.data[event.previousIndex]
}
}
else
{
if (event.container.data.src===undefined && event.previousContainer.data.src!==undefined)
event.previousContainer.data.src=null;
}
}
}
Update 如果我们使用两个 mat-grid-list,我们确实可以改进代码。一个用于“board”,另一个用于“side”
<div class="content" cdkDropListGroup>
<div #board class="board">
<mat-grid-list cols="5">
...
</mat-grid-list>
</div>
<div class="side">
<mat-grid-list cols="1">
<mat-grid-tile *ngFor="let cell of icons; let i = index">
<div
class="cell"
cdkDropList
[cdkDropListData]="cell"
(cdkDropListDropped)="drop($event)"
>
<div cdkDrag>
<img [src]="cell" width="100%" />
<div *cdkDragPlaceholder></div>
</div>
</div>
</mat-grid-tile>
</mat-grid-list>
</div>
</div>
看到这个想法是相似的,而不是使用一个独特的cdkDropList,因为我们可以使用我们拥有的那么多的cdkDropList。这允许我们在“拖动”时不会重新排列图标列表。此外,我们可以使用 .css - 看到它正在考虑 5x5 的网格 - 使“图标”的大小与我们的棋盘图块相同。这允许我们不使用 cdkPreview 因为所有的“图标”具有相同的大小。
.content
{
display:flex;
justify-content: space-between;
position:relative;
}
.board{
flex-basis:80%;
position:relative;
}
.board::affter
{
content:' '
}
.side{
flex-basis:16%;
}
.cell{
width:100%;
height:100%;
}
代码中唯一的变化是,当我们让 drop 使用并删除函数“CalculeMargin”时
if (event.previousContainer.data.src!=undefined)
{
....
}
else
{
//see that the data is the "src" of the icon
event.container.data.src=event.previousContainer.data
}
我使用 angular 设计了一个网格。我将从图像列表中拖出一些图像并将它们放入网格图块中。下面附上设计图
这是我的打字稿代码
officeItems = [Image's URL];
drop(event: CdkDragDrop<string[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(
event.container.data,
event.previousIndex,
event.currentIndex
);
} else {
copyArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex
);
}
}
HTML代码
<div class="row">
<div class="col-10" cdkDropList #cellList="cdkDropList" [cdkDropListData]="cells" [cdkDropListConnectedTo]="[itemList]">
<mat-grid-list cols="10" >
<mat-grid-tile *ngFor="let cell of cells" [style.background]="cell.color">
<img *ngIf="cell.url" src="{{cell.url}}"/>
</mat-grid-tile>
</mat-grid-list>
</div>
<div class="col-2" cdkDropList #itemList="cdkDropList" [cdkDropListData]="officeItems" [cdkDropListConnectedTo]="[cellList]" (cdkDropListDropped)="drop($event)">
<pre *ngFor="let item of officeItems" cdkDrag><img src= "{{item}}" title="Sofa" style="margin-top: 10px;"/></pre>
</div>
</div>
ts文件中有两个数据数组
cells= [
{ id: 1, minDistanceToA: 0.0 },
{ id: 2, minDistanceToA: 1.0 },
{ id: 3, minDistanceToA: 2.0 },
{ id: 4, minDistanceToA: 3.0 },
{ id: 5, minDistanceToA: 4.0 }];
officeItems: any = ['../assets/images/sofa1.png', '../assets/images/chair.png'}];
我可以拖动图像但不能放下它们。当我尝试删除时,它再次替换为之前的 div
我试过使用您的代码,并在一天的前半天进行了处理。 我得出的结论是,结合 mat-grid 和 cdkDropList 是个坏主意。 不过,我可以告诉您的是,使用 copyArrayItem 并不能使您到达想要的位置。
改用这个:
onDrop(event: CdkDragDrop<cell[]>) {
if (!(event.previousContainer === event.container)){
event.container.data[event.currentIndex] =
event.previousContainer.data[event.previousIndex];
}
}
这将做什么:
容器:包含 cdkDragDrop 项目的数组
Index: 用于挑选单件商品
- 获取您正在将另一个项目拖入的项目(当前索引处的当前容器数组)
- 将其替换为您当前正在拖动的项目(上一个索引处的上一个容器数组)
我知道我迟到了,但是...
在“网格”中管理 cdk 拖放非常复杂,因为 material angular cdkDropList 考虑单维
想法总是一样的,而不是使用唯一的 cdkDropList,我们可以创建如此多的 cdkDropList 作为我们拥有的元素 - 在外面的情况下,网格。全部包含在 div 和 cdkDropListGroup
-
<div class="content" cdkDropListGroup>
<div #board class="board">
<mat-grid-list cols="5">
<mat-grid-tile *ngFor="let cell of cells; let i = index">
<div
class="cell"
cdkDropList
[cdkDropListData]="cell"
(cdkDropListDropped)="drop($event)"
[style.background]="i == indexOver ? 'red' : 'yellowgreen'"
(mouseover)="this.indexOver = i"
(mouseout)="indexOver = -1"
>
<div cdkDrag>
<img
*ngIf="cell.src"
[src]="cell.src"
width="100%"
/>
<span *ngIf="!cell.src"></span>
<div *cdkDragPlaceholder></div>
</div>
</div>
</mat-grid-tile>
</mat-grid-list>
</div>
<div
class="side"
cdkDropList
sortingDisabled="true"
[cdkDropListData]="icons"
(cdkDropListDropped)="drop($event)"
>
<div *ngFor="let icon of icons">
<div cdkDrag (mousedown)="calculeMargin($event)">
<img [src]="icon" />
<img
*cdkDragPreview
[src]="icon"
[ngStyle]="previewStyle ? previewStyle : null"
/>
<div *cdkDragPlaceholder></div>
</div>
</div>
</div>
</div>
我们的 mat-grid-tile 将是“cdkDrag”,这会根据 cell.src 的值显示 img 或 span。看到我们创建了一个“空”*cdkDragPlaceholder
在另一边,我们有一个典型的列表。我们转换 cdkDragPreview 使我们拖动元素时与我们的“tiles”大小相同(这是 (mousedown)="calculeMargin($event")
我使用相同的函数“drop”来控制所有的drop。为了检查我们是从“板”还是从“侧面”拖动,我使用了自己的“数据”。如果有一个 属性 "src" 是板上的一个项目,否则是侧面的一个项目。看到我们不使用“传输”或其他“奇怪的功能”,否则只需压入或更改数组的元素
indexOver:number=-1;
previewStyle: any = null;
@ViewChild(MatGridTile, { static: false, read: ElementRef }) model;
@ViewChild('board', { static: false,read:ElementRef })board:ElementRef;
icons = [
'https://picsum.photos/100/100?random=1',
'https://picsum.photos/100/100?random=2',
'https://picsum.photos/100/100?random=3',
];
cells = Array(25).fill(' ').map((_,index)=>({src:null,id:index}));
constructor() {}
ngOnInit() {
setTimeout(() => {
const rect = this.model.nativeElement.getBoundingClientRect();
this.previewStyle = {
width: rect.width + 'px',
height: rect.height + 'px',
};
});
}
calculeMargin(event: MouseEvent) {
const rect = this.model.nativeElement.getBoundingClientRect();
this.previewStyle = {
width: rect.width + 'px',
height: rect.height + 'px',
'margin-top': -event.offsetY + 'px',
'margin-left': -event.offsetX + 'px',
};
}
drop(event: CdkDragDrop<any>) {
if (event.previousContainer != event.container) {
if (event.container.data.src!==undefined)
{
if (event.previousContainer.data.src!=undefined)
{
event.container.data.src=event.previousContainer.data.src
event.previousContainer.data.src=null;
}
else
{
event.container.data.src=event.previousContainer.data[event.previousIndex]
}
}
else
{
if (event.container.data.src===undefined && event.previousContainer.data.src!==undefined)
event.previousContainer.data.src=null;
}
}
}
Update 如果我们使用两个 mat-grid-list,我们确实可以改进代码。一个用于“board”,另一个用于“side”
<div class="content" cdkDropListGroup>
<div #board class="board">
<mat-grid-list cols="5">
...
</mat-grid-list>
</div>
<div class="side">
<mat-grid-list cols="1">
<mat-grid-tile *ngFor="let cell of icons; let i = index">
<div
class="cell"
cdkDropList
[cdkDropListData]="cell"
(cdkDropListDropped)="drop($event)"
>
<div cdkDrag>
<img [src]="cell" width="100%" />
<div *cdkDragPlaceholder></div>
</div>
</div>
</mat-grid-tile>
</mat-grid-list>
</div>
</div>
看到这个想法是相似的,而不是使用一个独特的cdkDropList,因为我们可以使用我们拥有的那么多的cdkDropList。这允许我们在“拖动”时不会重新排列图标列表。此外,我们可以使用 .css - 看到它正在考虑 5x5 的网格 - 使“图标”的大小与我们的棋盘图块相同。这允许我们不使用 cdkPreview 因为所有的“图标”具有相同的大小。
.content
{
display:flex;
justify-content: space-between;
position:relative;
}
.board{
flex-basis:80%;
position:relative;
}
.board::affter
{
content:' '
}
.side{
flex-basis:16%;
}
.cell{
width:100%;
height:100%;
}
代码中唯一的变化是,当我们让 drop 使用并删除函数“CalculeMargin”时
if (event.previousContainer.data.src!=undefined)
{
....
}
else
{
//see that the data is the "src" of the icon
event.container.data.src=event.previousContainer.data
}