使用 Angular 7 Material CDK 嵌套拖放

问题描述:

我有一个拖放列表的嵌套树(不是树组件).

I've got a nested tree (Not the tree component) of drag and drop lists.

在包含在另一个下拉列表内的下拉列表中拖动项目时 - 两个下拉列表的 Enter/Exit 事件都会触发,这意味着当一个项目被删除时,它可以被放到内部下拉列表或容器中删除列表取决于它被删除的位置(注意:这些列表都相互链接)

When dragging items around in drop lists that are contained inside of another drop list - Enter / Exit events are firing for both drop lists, meaning that when an item is dropped it could either be dropped into the inner drop list or the container drop list depending where it was dropped (Note: These lists are all linked to each other)

我目前在想,如果拖动当前位于内部列表上,则最好的解决方案是抑制为容器列表触发的事件,但我不确定这是否是最佳解决方案或具体怎么做此刻它.

I'm thinking at the moment that the best solution will to be suppress events firing for the container list if the drag is currently over an inner list but I'm not sure if this is the best solution or exactly how to do it at the moment.

我确实设法找到了解决方案,尽管它绝对是 hacky 并且涉及使用 Angular 拖放 CDK 访问私有值.

I did manage to find a solution to this, although it's definitely hacky and involves accessing a private value with the Angular drag and drop CDK.

我使用 cdkDropListEnterPredicate 函数来检查它应该尝试放入哪个列表,我分配了 canDropPredicate 函数.

I use the cdkDropListEnterPredicate function to check which list it should be trying to drop into, which i assign the canDropPredicate function.

我还*通过以下方式访问指针位置:_pointerPositionAtLastDirectionChange 这不是很好,因为并非我希望看到的所有值都传递到 cdkDropListEnterPredicate 中.

I'm also forced to get access to the pointer position via: _pointerPositionAtLastDirectionChange which isn't great as not all the values I'd like to see passed into the cdkDropListEnterPredicate get passed.

canDropPredicate(): Function {
    const me = this;
    return (drag: CdkDrag<ResourceNode>, drop: CdkDropList<ResourceNode>): boolean => {
        const fromBounds = drag.dropContainer.element.nativeElement.getBoundingClientRect();
        const toBounds = drop.element.nativeElement.getBoundingClientRect();

        if (!me.intersect(fromBounds, toBounds)) {
            return true;
        }

        // This gross but allows us to access a private field for now.
        const pointerPosition: Point = drag['_dragRef']['_pointerPositionAtLastDirectionChange'];
        // They Intersect with each other so we need to do some calculations here.
        if (me.insideOf(fromBounds, toBounds)) {
          return !me.pointInsideOf(pointerPosition, fromBounds);
        }

        if (me.insideOf(toBounds, fromBounds) && me.pointInsideOf(pointerPosition, toBounds)) {
          return true;
        }
         return false;
    };
}

intersect(r1: DOMRect | ClientRect, r2: DOMRect | ClientRect): boolean {
    return !(r2.left > r1.right ||
        r2.right < r1.left ||
        r2.top > r1.bottom ||
        r2.bottom < r1.top);
}

insideOf(innerRect: DOMRect | ClientRect, outerRect: DOMRect | ClientRect): boolean {
    return innerRect.left >= outerRect.left &&
        innerRect.right <= outerRect.right &&
        innerRect.top >= outerRect.top &&
        innerRect.bottom <= outerRect.bottom &&
        !(
            innerRect.left === outerRect.left &&
            innerRect.right === outerRect.right &&
            innerRect.top === outerRect.top &&
            innerRect.bottom === outerRect.bottom
        );
}

pointInsideOf(position: Point, rect: DOMRect | ClientRect) {
  return position.x >= rect.left &&
        position.x <= rect.right &&
        position.y >= rect.top &&
        position.y <= rect.bottom;
}