滚动页面时打开上面的 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
我在 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