У меня есть компонент, основанный на этом стеке: https://stackblitz.com/edit/angular-5mf7hl
Проблема возникает, когда я пытаюсь поменять элементы в списке. Я хочу, чтобы элементы массива менялись местами. В приведенном выше примере stackblitz целевой listItem перемещается вперед или назад во время предварительного просмотра в списке, когда он заменяется sourceItem. Мне удалось заставить их поменяться местами, позаимствовав некоторый код у Синдзё в этом вопросе StackOverflow: Angular 7 drag Перетаскивать элементы подкачки
Однако сама перестановка работает отлично, когда я перетаскиваю элемент списка поверх другого элемента списка, предварительный просмотр неправильный. Когда вы отпускаете, он исправляет себя, и listItem появляется в правильном месте в массиве. Что я хочу, так это чтобы исходный элемент списка и целевой элемент списка менялись местами во время предварительного просмотра, прежде чем разрешить go перетаскиваемого элемента. Вы можете взглянуть на вышеприведенный стек, чтобы увидеть проблему.
App.component.ts
import { Component, NgModule, ViewChild } from '@angular/core';
import {
CdkDrag,
CdkDragStart,
CdkDropList, CdkDropListContainer, CdkDropListGroup,
moveItemInArray
} from "@angular/cdk/drag-drop";
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
@ViewChild(CdkDropListGroup) listGroup: CdkDropListGroup<CdkDropList>;
@ViewChild(CdkDropList) placeholder: CdkDropList;
public items: Array<number> = [1, 2, 3, 4, 5, 6, 7, 8, 9];
public target: CdkDropList;
public targetIndex: number;
public source: CdkDropListContainer;
public sourceIndex: number;
constructor() {
this.target = null;
this.source = null;
}
ngAfterViewInit() {
let phElement = this.placeholder.element.nativeElement;
phElement.style.display = 'none';
phElement.parentNode.removeChild(phElement);
}
drop() {
if (!this.target)
return;
let phElement = this.placeholder.element.nativeElement;
let parent = phElement.parentNode;
phElement.style.display = 'none';
parent.removeChild(phElement);
parent.appendChild(phElement);
parent.insertBefore(this.source.element.nativeElement,
parent.children[this.sourceIndex]);
this.target = null;
this.source = null;
if (this.sourceIndex != this.targetIndex) {
let oldtarget = this.items[this.sourceIndex];
this.items[this.sourceIndex] = this.items[this.targetIndex];
this.items[this.targetIndex] = oldtarget;
}
}
enter = (drag: CdkDrag, drop: CdkDropList) => {
if (drop == this.placeholder)
return true;
let phElement = this.placeholder.element.nativeElement;
let dropElement = drop.element.nativeElement;
let dragIndex = __indexOf(dropElement.parentNode.children,
drag.dropContainer.element.nativeElement);
let dropIndex = __indexOf(dropElement.parentNode.children, dropElement);
if (!this.source) {
this.sourceIndex = dragIndex;
this.source = drag.dropContainer;
let sourceElement = this.source.element.nativeElement;
phElement.style.width = sourceElement.clientWidth + 'px';
phElement.style.height = sourceElement.clientHeight + 'px';
sourceElement.parentNode.removeChild(sourceElement);
}
this.targetIndex = dropIndex;
this.target = drop;
phElement.style.display = '';
dropElement.parentNode.insertBefore(phElement, (dragIndex < dropIndex)
? dropElement.nextSibling : dropElement);
this.source.start();
this.placeholder.enter(drag, drag.element.nativeElement.offsetLeft,
drag.element.nativeElement.offsetTop);
return false;
}
}
function __indexOf(collection, node) {
return Array.prototype.indexOf.call(collection, node);
};
App.component. html
<div class="example-container" cdkDropListGroup>
<div cdkDropList [cdkDropListEnterPredicate]="enter" (cdkDropListDropped)="drop()" #placeholder></div>
<div cdkDropList *ngFor="let item of items"
[cdkDropListEnterPredicate]="enter" (cdkDropListDropped)="drop()">
<div cdkDrag class="example-box">{{item}}</div>
</div>
</div>
App.component. css
.example-list {
list-style-type: none;
padding: 0;
}
.example-list li {
display: table-cell;
padding: 4px;
}
.example-container {
display: flex;
flex-wrap: wrap;
min-width: 600px;
max-width: 900px;
}
.example-box {
width: 200px;
height: 200px;
border: solid 1px #ccc;
font-size: 30pt;
font-weight: bold;
color: rgba(0, 0, 0, 0.87);
cursor: move;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
background: #fff;
border-radius: 4px;
position: relative;
z-index: 1;
transition: box-shadow 200ms cubic-bezier(0, 0, 0.2, 1);
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2),
0 2px 2px 0 rgba(0, 0, 0, 0.14),
0 1px 5px 0 rgba(0, 0, 0, 0.12);
}
.example-box:active {
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12);
opacity: .6;
}
.cdk-drop-list {
display: flex;
padding-right: 10px;
padding-bottom: 10px;
}
.cdk-drag-preview {
box-sizing: border-box;
border-radius: 4px;
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
.cdk-drag-placeholder {
opacity: .3;
}
.cdk-drag-animating {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}