滚动页面时打开上面的 angular material 工具提示,避免工具提示被隐藏

To open angular material tooltip above when the page is scrolled and avoid the tooltip getting hidden

我在 stackblitz link 中添加了 2 table,如果我将鼠标悬停在第一个 table(第一列)最后几行,工具提示将在上方打开(expected) 但是当我们向下滚动页面然后将鼠标悬停在 2nd table 的最后一行时,工具提示隐藏在屏幕底部,因为如果我有一个 table,情况就不是这样了。 我期待工具提示在上方打开而不是隐藏在底部。请推荐。

闪电战 link

https://stackblitz.com/edit/angular-mat-tooltip-ctvigc?file=app%2Ftooltip-overview-example.html

tooltip-overview-example.html

<ng-container matColumnDef="Column1">
     <th mat-header-cell *matHeaderCellDef mat-sort-header> Alert </th>

     <td mat-cell *matCellDef="let row; let i = index" customToolTip [contentTemplate]="template">
          <span >{{row.Column1}}</span>
     <!--TOOLTIP-->
      <ng-template #template>
          <div style="display: flex; flex-direction: column">
             <span>{{row.conditionals | json}}</span>
             <button (click)="onClick(i)">Click</button>
          </div>
      </ng-template>
      </td>

</ng-container>

扩展了 CustomToolTipComponent 中的 Angular material TooltipComponent

自定义工具-tip.component.ts

import {
 Component,
 OnInit,
 OnDestroy,
 Input,
 TemplateRef
 } from "@angular/core";
 import {TooltipComponent} from "@angular/material/tooltip"
 import { Observable, Subject } from "rxjs";

@Component({
 selector: "app-custom-tool-tip",
 templateUrl: "./custom-tool-tip.component.html",
 styleUrls: ["./custom-tool-tip.component.css"]
})
export class CustomToolTipComponent extends TooltipComponent {

 @Input() text: string;
 @Input() contentTemplate: TemplateRef<any>;

}

自定义工具-tip.component.html

<div>
 <div class="tooltip-conatiner">
  <ng-template #simpleText>
  {{text}}
  </ng-template>
  <ng-container *ngTemplateOutlet="contentTemplate || simpleText">
  </ng-container>
</div>
</div>

工具提示-renderer.directive.ts

@Directive({
  selector: "[customToolTip]"
})
export class ToolTipRendererDirective {

@Input() showToolTip: boolean = true;

//If this is specified then specified text will be showin in the tooltip
 @Input(`customToolTip`) text: string;

//If this is specified then specified template will be rendered in the tooltip
 @Input() contentTemplate: TemplateRef<any>;

private _overlayRef: OverlayRef;
private _tooltipInstance;
private _mouseInTooltip: boolean = false;
private _hasListeners: boolean = false;

constructor(
 private _overlay: Overlay,
 private _overlayPositionBuilder: OverlayPositionBuilder,
 private _elementRef: ElementRef,
 private _r2: Renderer2
 ) {}


ngOnInit() {
 if (!this.showToolTip) {
  return;
}

const positionStrategy = this._overlayPositionBuilder
  .flexibleConnectedTo(this._elementRef)
  .withPositions([
    {
      originX: "center",
      originY: "bottom",
      overlayX: "center",
      overlayY: "top",
      offsetY: -10
    }
  ]);

this._overlayRef = this._overlay.create({ positionStrategy });
}


@HostListener("mouseenter")
show(e) {
if (this._overlayRef && !this._overlayRef.hasAttached()) {
  //set tooltip instance
  this._tooltipInstance = this._overlayRef.attach(
    new ComponentPortal(CustomToolTipComponent)
  ).instance;

  //set CustomToolTipComponenet content/inputs
  this._tooltipInstance.text = this.text;
  this._tooltipInstance.contentTemplate = this.contentTemplate;

  //render tooltip
  this._tooltipInstance!.show(0);

  //sub to detach after hide anitmation is complete
  this._tooltipInstance
    .afterHidden()
    .pipe(take(1))
    .subscribe(() => {
      this._overlayRef.detach();
    });
  if (!this._hasListeners) {
    this._hasListeners = true;
    //attach mouseleave listener to detach when mouseleave on tooltip
    this._r2.listen(this._overlayRef.overlayElement, "mouseleave", () => {
      //call hide function in this directive
      this._mouseInTooltip = false;
      this.hide();
    });

    this._r2.listen(this._overlayRef.overlayElement, "mouseenter", () => {
      //call hide function in this directive
      this._mouseInTooltip = true;
    });
  }
}
}

@HostListener("mouseleave")
hide(buttonClicked = null) {
if(buttonClicked)
  this._mouseInTooltip = false;
setTimeout(() => {
  if (!this._mouseInTooltip) this._tooltipInstance!._onHide.next();
}, 20);
}
}

您可以获得 event.screenX 和事件 event.screenY 位置,并使用它通过获取屏幕高度和屏幕宽度检查屏幕高度。

screen.height

然后检查事件是否不接近屏幕高度,如果然后使 [matTooltipPosition]="position.value" 高于..

像这样你必须检查

要解决这个问题,您需要将您的 cdk 版本升级到 7.3.7,它在 OverlayRef 上有一个新方法作为 updatePositionStrategy。

按照这个方法可以改变一个overlay在attach后的位置策略

在附加组件后的显示函数中,您需要更新位置策略,如下所示:

this._overlayRef.updatePositionStrategy(this._overlayPositionBuilder
  .flexibleConnectedTo(this._elementRef)
  .withPositions([{
    originX: "center",
    originY: "bottom",
    overlayX: "center",
    overlayY: "top",
    offsetY: this.getOffsetY()
  }]));
this._overlayRef.updatePosition();

其中 this.getOffsetY() 是私有方法,提供基于元素当前位置的偏移 y 值。您可能需要更新此逻辑。

private getOffsetY() {
  if (this._elementRef.nativeElement.getBoundingClientRect().bottom > 500)
    return -400;
  if (this._elementRef.nativeElement.getBoundingClientRect().bottom > 400)
    return -300;
  if (this._elementRef.nativeElement.getBoundingClientRect().bottom > 300)
    return -200;
  return -10;
}

这里是 stackblitz link