簡體   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