创建一个采用元素内容并使用它添加新元素的Angular 5指令的正确方法

时间:2018-02-15 06:10:23

标签: angular angular5

我希望在Angular 5中创建一个指令,我可以将其应用于一个元素,该元素将获取元素的所有内容(包括模板绑定和子组件),并在DOM中创建一个新元素嵌入的所有内容。

示例:

<div directiveImTryingToMake>
  <center>
    <span>{{randomBinding}}</span>
  </center>
</div>

应在悬停时输出:

<div directiveImTryingToMake>
  <center>
    <span>{{randomBinding}}</span>
  </center>
  <directive-content>
    <center>
      <span>{{randomBinding}}</span>
    </center>
  </directive-content>
</div>

当悬停离开指令内容时,应该返回到此状态,在我的情况下将覆盖原始内容:

<div directiveImTryingToMake>
  <center>
    <span>{{randomBinding}}</span>
  </center>
</div>

但也许一个指令是完成这个的错误方法。我试图扩展表格单元格的内容,并在用户将鼠标悬停在我将应用指令的元素上时将其覆盖在其他元素上。我见过的所有解决方案都使用了大量的Angular库。我正在寻找一些简单而高效的东西。

提前致谢!

1 个答案:

答案 0 :(得分:0)

我不得不开发类似的东西(在Angular 7中)。

我创建了一个指令,该指令自动将DIV添加到充当叠加层的父元素中。它在mouseEnter和mouseLeave上触发。

指令代码在这里:

import { Directive, ElementRef, HostListener, Input, Renderer2 } from 
"@angular/core";

@Directive({
   // tslint:disable-next-line:directive-selector
   selector: "[overlay]"
})
export class OverlayDirective {
    @Input() public overlayCondition: boolean;
    @Input() public overlayHtml: string;
    @Input() public overlayCssClass: string;

   private overlayDiv: string;

   constructor(private el: ElementRef,
            private renderer: Renderer2) {
   }

   @HostListener("mouseenter") 
   public onMouseEnter() {
        if (!this.overlayCondition) {
             return;
        }

        this.overlayDiv = this.renderer.createElement("div");
        if (this.overlayCssClass) {
            this.renderer.addClass(this.overlayDiv, this.overlayCssClass);
        }
        this.renderer.appendChild(this.el.nativeElement, this.overlayDiv);
        this.el.nativeElement.lastChild.innerHTML = this.overlayHtml;

        this.renderer.setStyle(this.overlayDiv, 
                               "height", 
                               `${this.el.nativeElement.offsetHeight}px`);
        this.renderer.setStyle(this.overlayDiv, 
                                "top", 
                                `${this.el.nativeElement.offsetTop}px`);
        this.renderer.setStyle(this.overlayDiv, 
                                "width", 
                                `${this.el.nativeElement.offsetWidth}px`);
        this.renderer.setStyle(this.overlayDiv, 
                                "left", 
                                `${this.el.nativeElement.offsetLeft}px`);
        this.renderer.setStyle(this.overlayDiv, "position", "absolute");
    }

    @HostListener("mouseleave") 
    public onMouseLeave() {
        if (!this.overlayCondition) {
            return;
        }

        this.renderer.removeChild(this.el.nativeElement, this.overlayDiv);
    }
}

您可以像这样使用它:

 <tr overlay [overlayCondition]="rowData.notSupported"
             [overlayHtml]="notSupportedHtml" 
             [overlayCssClass]="'not-supported-overlay'">
    ...
 </tr>

在我的案例中,scss类是:

    .not-supported-overlay {
        border-top:1px solid $grey-6;
        box-sizing:border-box;
        position:absolute;
        background-color: rgba(255,255,255,0.9);
        display: flex;
        align-items:center;
        justify-content:center;

        pointer-events: none !important;

        * {
            pointer-events: auto;
        }

        .button {
            margin-left:20px;
        }
     }