监听子组件外部的点击事件?

huangapple go评论85阅读模式
英文:

How to listen for clicks outside a child component?

问题

I need to know if it is being clicked outside the CHILD COMPONENT, so I can close it.

我需要知道是否在子组件外部进行了点击,以便我可以关闭它。

I can't use mouseover any of that.

我不能使用mouseover来实现这个。

I'm using HostListener, but in the target it always sees the parent of the element and never the child.

我正在使用HostListener,但在目标中它总是看到元素的父级,而不是子级。

  1. @HostListener('document:click', ['$event.target'])
  2. public onClick(target) {
  3. console.log(target)
  4. }
  5. constructor(private _elementRef: ElementRef) {}

An example of what happens is the following, I have the following structure:

一个示例是,我有如下结构:

  1. <componentA>
  2. <componentB />
  3. </componentA>

I want to know if the click is being made outside of componentB, but with the code above, it is only listening to componentA.

我想知道点击是否发生在componentB的外部,但是使用上述代码,它只会监听componentA。

英文:

I need to know if it is being clicked outside the CHILD COMPONENT, so I can close it.

I can't use mosueover any of that.

I'm using Hostlistenner, but in the target it always sees the parent of the element and never the child.

  1. @HostListener(&#39;document:click&#39;, [&#39;$event.target&#39;])
  2. public onClick(target) {
  3. console.log(target)
  4. }
  5. constructor(private _elementRef: ElementRef) {}

An example of what happens is the following, I have the following structure:

  1. &lt;componentA&gt;
  2. &lt;componentB /&gt;
  3. &lt;/componentA&gt;

I want to know if the click is being made outside of componentB, but with the code above, it is only listening to componentA.

监听子组件外部的点击事件?

答案1

得分: 0

以下是翻译好的内容:

你需要明确检查被点击的 DOM 元素,因为监听 document 上的点击事件会始终将点击事件视为针对整个文档的点击(这是相当明显的)。所以你需要在子组件中导入 ElementRef 并使用它来检查子组件是否是点击事件的实际目标:

  1. import { HostListener } from '@angular/core'; // 以及来自 /core 的其他模块
  2. (...)
  3. constructor(private elem: ElementRef) {}
  4. @HostListener('document:click', ['$event'])
  5. docClicked(event: Event) {
  6. if (this.elem.nativeElement.contains(event.target))
  7. console.log('点击在内部');
  8. else {
  9. console.log('点击在外部');
  10. }
  11. }
  12. 然后你可以在 docClicked/else 块中执行你想要的操作。
  13. 检查 [stackblitz 示例][1] 以发射到父组件方法,该方法将设置控制在父模板中显示子组件的变量为 false
  14. [1]: https://stackblitz.com/edit/angular-ivy-urtm6r?file=src%2Fapp%2Fapp.component.html,src%2Fapp%2Fchild%2Fchild.component.ts
  15. <details>
  16. <summary>英文:</summary>
  17. You need to explicitely check for the clicked DOM element, because listening to click on `document` will always treat the click as targetting the document as a whole (which is rather obvious). So you need to import `ElementRef` into child component and use it to check if the child is the actual target of the click:
  18. import { HostListener } from &#39;@angular/core&#39;; // and other modules from /core
  19. (...)
  20. constructor(private elem: ElementRef) {}
  21. @HostListener(&#39;document:click&#39;, [&#39;$event&#39;])
  22. docClicked(event: Event) {
  23. if (this.elem.nativeElement.contains(event.target))
  24. console.log(&#39;clicked inside&#39;);
  25. else {
  26. console.log(&#39;clicked outside&#39;);
  27. }
  28. }
  29. Then you can do what you want in the docClicked/else block.
  30. Check [stackblitz example][1] for emitting to parent method that will set to false the var that controls the display of the child component in the parent template.
  31. [1]: https://stackblitz.com/edit/angular-ivy-urtm6r?file=src%2Fapp%2Fapp.component.html,src%2Fapp%2Fchild%2Fchild.component.ts
  32. </details>
  33. # 答案2
  34. **得分**: 0
  35. 我注意到除了获取父组件而不是子组件之外,在生产环境中`document`会返回undefined,为了修复这两个问题,使用了以下代码:
  36. import { Inject, ElementRef } from '@angular/core';
  37. import { DOCUMENT } from '@angular/common';
  38. this.isOpened: boolean = false;
  39. constructor(
  40. @Inject(DOCUMENT) private _document: Document,
  41. private _elementRef: ElementRef
  42. ) {}
  43. ngOnInit(): void {
  44. this._handleOnDocumentClick();
  45. }
  46. ngOnDestroy(): void {
  47. this.removeEventListener('click', this._handleOnDocumentClick, true)
  48. }
  49. private _handleOnDocumentClick(): void {
  50. this._document.addEventListener('click', (event: Event) => {
  51. event.composedPath().includes(this._elementRef.nativeElement)
  52. ? this.isOpened = !this.isOpened
  53. : this.isOpened = false;
  54. });
  55. }
  56. <details>
  57. <summary>英文:</summary>
  58. I noticed that in addition to being getting the parent component and not the child, in production the `document` was giving undefined, so to correct both, the following code was used:
  59. import { Inject, ElementRef } from &#39;@angular/core&#39;;
  60. import { DOCUMENT } from &#39;@angular/common&#39;;
  61. this.isOpened: boolean = false;
  62. constructor(
  63. @Inject(DOCUMENT) private _document: Document,
  64. private _elementRef: ElementRef
  65. ) {}
  66. ngOnInit(): void {
  67. this._handleOnDocumentClick();
  68. }
  69. ngOnDestroy(): void {
  70. this.removeEventListener(&#39;click&#39;, this._handleOnDocumentClick, true)
  71. }
  72. private _handleOnDocumentClick(): void {
  73. this._document.addEventListener(&#39;click&#39;, (event: Event) =&gt; {
  74. event.composedPath().includes(this._elementRef.nativeElement)
  75. ? this.isOpened = !this.isOpened
  76. : this.isOpened = false;
  77. });
  78. }
  79. </details>

huangapple
  • 本文由 发表于 2023年5月22日 23:08:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76307560.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定