繁体   English   中英

使用 Angular 7 Material CDK 嵌套拖放

[英]Nested Drag and Drop in with Angular 7 Material CDK

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

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

我目前在想,如果拖动当前位于内部列表上,则最好的解决方案是抑制为容器列表触发的事件,但我不确定这是否是最佳解决方案或确切的方法片刻。

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

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

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

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;
}

此解决方案的问题在于,谓词不会影响拖动起源的 CdkDropList 中已经进行的拖动。

这是一个问题,因为当将对象“向上”移动时,层次结构起作用(因为谓词函数),例如移动它的兄弟项下的一个项目,层次结构中的“向下”会导致 2 个 CdkDropLists 区域不可避免的重叠,这将导致竞争健康)状况。

这是需要解决的主要问题 -如何任意告诉父 CdkDropList “停止考虑” CdkDrag(对拖动做出反应),同时仍然能够有效地将其放入子 CdkDropList

或者换句话说 - 让所有的 CdkDropLists 被 X,Y 的 Z 轴穿过,由指针位置标记,选择一个面积最小的(“最年轻的”),并使其余的“不响应”当前拖动。

我建议遵循这种方法,将有帮助

https://stackblitz.com/edit/angular-cdk-nested-drag-drop-demo

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM