嵌套拖放 Angular 7 Material CDK
Nested Drag and Drop in with Angular 7 Material CDK
我有一个嵌套的拖放列表树(不是树组件)。
当在包含在另一个下拉列表中的下拉列表中四处拖动项目时 - 两个下拉列表都会触发进入/退出事件,这意味着当一个项目被放下时,它可能会被放入内部下拉列表或容器掉落列表取决于它掉落的位置(注意:这些列表都相互链接)
我目前在想,如果拖动当前位于内部列表上方,最好的解决方案是抑制为容器列表触发的事件,但我不确定这是否是最佳解决方案或究竟如何现在就去做。
我确实设法找到了解决这个问题的方法,尽管它绝对是 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 中正在进行的拖拽,拖拽起源于此。
这是一个问题,因为在移动对象时 'up' 层次结构起作用(因为谓词函数),例如,移动它的兄弟项下的一个项目,层次结构中的 'down' 会导致不可避免的重叠将导致竞争条件的 2 个 CdkDropLists 区域。
这是需要解决的主要问题 - 如何任意告诉父级 CdkDropList 到 'stop considering' CdkDrag(对拖动做出反应)同时仍然能够有效地将其放入子级CdkDropList
或者换句话说 - 获取所有被指针位置标记的 X,Y 的 Z 轴穿透的 CdkDropLists,选择面积最小的一个('youngest')并使其余的 'non responsive'到当前拖动。
我有一个嵌套的拖放列表树(不是树组件)。
当在包含在另一个下拉列表中的下拉列表中四处拖动项目时 - 两个下拉列表都会触发进入/退出事件,这意味着当一个项目被放下时,它可能会被放入内部下拉列表或容器掉落列表取决于它掉落的位置(注意:这些列表都相互链接)
我目前在想,如果拖动当前位于内部列表上方,最好的解决方案是抑制为容器列表触发的事件,但我不确定这是否是最佳解决方案或究竟如何现在就去做。
我确实设法找到了解决这个问题的方法,尽管它绝对是 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 中正在进行的拖拽,拖拽起源于此。
这是一个问题,因为在移动对象时 'up' 层次结构起作用(因为谓词函数),例如,移动它的兄弟项下的一个项目,层次结构中的 'down' 会导致不可避免的重叠将导致竞争条件的 2 个 CdkDropLists 区域。
这是需要解决的主要问题 - 如何任意告诉父级 CdkDropList 到 'stop considering' CdkDrag(对拖动做出反应)同时仍然能够有效地将其放入子级CdkDropList
或者换句话说 - 获取所有被指针位置标记的 X,Y 的 Z 轴穿透的 CdkDropLists,选择面积最小的一个('youngest')并使其余的 'non responsive'到当前拖动。