Angular Перетаскивание элементов абсолютной позиции при выборе неверного индекса - PullRequest
2 голосов
/ 03 мая 2020

Я пытаюсь перетащить элементы по двум спискам. Нижний список представляет собой типичный отсортированный список (например, «инвентарь»), но я хочу, чтобы верхние элементы были нигде не отсортированы и не могли быть сброшены (например, «игровая доска»).

У меня он работает, однако при опускании в верхний блок event.currentIndex всегда равен 0. Но при перетаскивании оттуда я получаю разные значения event.previousIndex, что означает, что элементы модели и DOM не всегда совпадают.

Вот stackblitz показывает, что я имею в виду. Перетащите несколько предметов в верхнее поле и поэкспериментируйте с ними, иногда вы заметите, что перемещается не тот предмет.

Это наиболее заметно, когда вы взаимодействуете в обратном порядке, например:

  1. Перетащите элементы «Один», «Два», «Три» в верхнее поле (в таком порядке)
  2. Попытайтесь вернуть предметы «Три», «Два», «Один» обратно в нижнюю ячейку (в указанном порядке)

enter image description here

1 Ответ

1 голос
/ 03 мая 2020
Опция

cdkDropListSortingDisabled работает только при перемещении предметов внутри одного контейнера. Если вы перемещаетесь из одного контейнера в другой, то Angular сортирует положение блоков:

this._itemPositions = this._activeDraggables.map(drag => {
  const elementToMeasure = drag.getVisibleElement();
  return {drag, offset: 0, clientRect: getMutableClientRect(elementToMeasure)};
}).sort((a, b) => {
  return isHorizontal ? a.clientRect.left - b.clientRect.left :
                        a.clientRect.top - b.clientRect.top;
});

Поскольку вы не указали ориентацию и по умолчанию используется вертикальная ориентация, она сортируется по top position.

Верхнее поле event.currentIndex всегда равно 0, потому что вы используете абсолютное позиционирование, а заполнитель всегда вверху.

Попробуйте добавить следующий стиль, чтобы увидеть, где отображается заполнитель:

.cdk-drag-placeholder {
  opacity: 1;
  background: red;
}

enter image description here

Чтобы исправить это, вы можете самостоятельно вычислить currentIndex, например, так:

const isWithinSameContainer = event .previousContainer === event.container;

let toIndex = event.currentIndex;
if (event.container.sortingDisabled) {
  const arr = event.container.data.sort((a, b) => a.top - b.top);
  const targetIndex = arr.findIndex(item => item.top > top);

  toIndex =
    targetIndex === -1
      ? isWithinSameContainer
        ? arr.length - 1
        : arr.length
      : targetIndex;
}

const item = event.previousContainer.data[event.previousIndex];
item.top = top;
item.left = left;

if (isWithinSameContainer) {
  moveItemInArray(event.container.data, event.previousIndex, toIndex);
} else {
  transferArrayItem(
    event.previousContainer.data,
    event.container.data,
    event.previousIndex,
    toIndex
  );
}

Разветвленный стек-блиц

...