角度拖放绝对位置元素选择了错误的索引

时间:2020-05-03 04:32:51

标签: angular angular-cdk-drag-drop

我正在尝试将项目拖到两个列表中。最下面的列表是典型的排序列表(例如“库存”),但我希望最上面的项目不排序并且可以在任何地方放置(例如“游戏板”)。

大多数情况下,它起作用,但是当放到顶盒中时event.currentIndex始终为0。但是从那里拖出时,我会得到不同的event.previousIndex值,这意味着模型和DOM元素并不总是匹配。

这是stackblitz,表示我的意思。将一些项目拖到顶部框中并进行操作,您会发现有时错误的项目会被移动。

以相反的顺序进行交互时最为明显,例如:

  1. 将“一个”,“两个”,“三个”项拖到顶部框中(按此顺序)
  2. 尝试将项目“三”,“二”,“一个”放回底部框中(按此顺序)

enter image description here

1 个答案:

答案 0 :(得分:1)

cdkDropListSortingDisabled选项仅在同一容器中移动项目时有效。如果您从一个容器移动到另一个容器,则块的角sorts位置:

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位置进行排序。

顶部框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
  );
}

Forked Stackblitz