我想做的是
stackblitz链接 -> stackblitz示例
组件的层次结构是这样的
中的'resize.directive'。
event.stopPropagation()
&.用于防止事件冒泡。event.preventDefault()
是用来防止事件冒泡的 孩子的组件
父组件
@HostListener('click', ['$event'])
当你把鼠标放在内部的子组件上时,你可以点击来拖动和调整元素的边框大小。
我的问题是 @HostListener
点击事件是从父组件中发出的,而我并不希望它是这样的。例如,如果你拖动子组件的边框,当鼠标向上时,父组件的点击事件就会发生。ParentComponent
被解雇。
我的理解是
stopPropagation()
但父组件仍在接收点击事件。
有很多关于使用 return false
......然而,根据其他问题,这似乎不是原因,如这里所示。
话说回来 return false
的指令,但事件仍在冒泡。
如果有任何关于我可能遗漏了什么的见解,我将不胜感激。
澄清一下,事件监听器将按照以下顺序被触发,从事件发生的元素开始。
directive -> child -> parent -> document
在我看来,你所遇到的问题归结为多种因素的结合。
当你拖动边框的时候 鼠标会停留在子元素的外面 所以你会最终触发了 parent.mouseup -> document.mouseup
. 要在指令中捕获事件,你必须监听到 document.mouseup
.
你的指令在听 document.mouseup
. 该 parent.mouseup
前被触发。document.mouseup
所以你无法阻止指令中的传播。
让我们看看当你把边界拖下来会发生什么。
你按下边界 这将触发 directive.mousedown -> child.mousedown -> ...
. 你在指令中停止了传播,所以一切正常。
你把鼠标拖到底部,光标现在在子元素外面。
你释放鼠标。请注意,我们已经不在子元素中了,所以这将会触发 parent.mouseup -> document.mouseup
. 父处理程序将在文档处理程序之前运行,所以你不能停止它。
由于 down
和 up
发生在父控制器内,点击现在被触发。同样的,我们在子元素之外,所以触发器为 parent.click -> document.click
. 你无法真正阻止这种情况发生,因为父处理程序是第一个处理程序。
我建议采用下面的解决方案,尽管它看起来有点黑。
HostListener('click')
我们可以滚动自己的:我们将听取 parent.mousedown
和 parent.mouseup
. 如果它们接连发生,我们就会认为这是一个点击,所以我们 "选择 "父体。// parent.component.ts
export class ParentComponent {
parentClicked: boolean = false;
down?: number;
manualClick(): void {
this.parentClicked = true;
console.log(`parent manual click`);
}
@HostListener('mousedown', ['$event'])
onMouseDown( event: MouseEvent): void {
console.log('parent down', event.target);
this.down = Date.now();
}
@HostListener('mouseup', ['$event'])
onMouseUp( event: MouseEvent): void {
console.log('parent up');
// Assume that if it's released within 100 ms, it's a click.
if (this.down && Date.now() - this.down < 100) {
this.manualClick();
this.down = undefined;
}
}
}
因为我们不监听点击事件,所以现在没事了。
parent.mousedown
永远不会发生。parent.mouseup -> document.mouseup
. 由于 parent.mousedown
没有被触发。down = undefined
,所以我们的 "点击逻辑 "并不能算作点击。document.mouseup
,最后在你的指令中处理它。现在,这里有一个小的潜在问题:当你在子元素中点击时,你会触发我们父元素的点击逻辑,因为child.mousedown-> parent.mousedown
随后是 child.mouseup -> parent.mouseup
. 如果你不希望这种情况发生,你可以停止传播的。mousedown
事件在孩子。
// child.component.ts
@HostListener('mousedown', ['$event'])
onMouseDown( event: MouseEvent): void {
console.log('child down');
event.stopPropagation();
event.preventDefault();
}