Обмен элементов в списке с помощью Angular CDK Drag and Drop и CDKDropListEnterPredicate - PullRequest
1 голос
/ 15 апреля 2020

У меня есть компонент, основанный на этом стеке: 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);
}
...