angular - 如何检测 Angular Material 选项卡内的滚动事件以及如何以编程方式滚动回顶部?

标签 angular angular-material angular11

在我的 Angular 应用程序(当前为 Angular 11)中,我总是使用一个返回顶部按钮,该按钮会在用户滚动时出现。单击该按钮后,该按钮会将窗口滚动回顶部,然后消失。经典行为。

但现在我更改了布局,并用 Angular Material Tabs 替换了引导导航栏。

我的 BodyComponent 现在看起来像这样:

<div id="body.component.container" style="margin-top: 62px;">
    <mat-tab-group [(selectedIndex)]="selectedMatTabIndex">
        <mat-tab>
            <ng-template matTabLabel>
                <span style="font-family: 'Arial Narrow', monospace; font-size: 16px; font-weight: bold;">Tab1</span>
            </ng-template>
            <app-content-component-001></app-content-component-001>
        </mat-tab>
    
        <mat-tab>
            <ng-template matTabLabel>
                <span style="font-family: 'Arial Narrow', monospace; font-size: 16px; font-weight: bold;">Tab2</span>
            </ng-template>
            <app-content-component-002></app-content-component-002>
        </mat-tab>
    </mat-tab-group>
</div>

<app-back-to-top
        [acceleration]="1000"
        [animate]="true"
        [scrollDistance]="50"
        [speed]="5000">
</app-back-to-top>

我面临的问题是,不再有可捕获的常见滚动事件。通常,正如大家肯定知道的那样,在返回顶部按钮组件内,我们会监听 HostEvent window:scroll 但这在 MatTabs 内不起作用。

  @HostListener('window:scroll', [])
  onWindowScroll() {
      if (this.isBrowser()) {
          this.animationState = this.getCurrentScrollTop() > this.scrollDistance / 2 ? 'in' : 'out';
      }
  }

我把这个返回顶部按钮组件放在哪里并不重要。我尝试将其直接放入 body 组件(多年来一直如此)、container-div、MatTabGroup 和每个 MatTab 中。 window:scroll 事件未显示。

在通过互联网进行(重新)搜索时,我发现了一些微弱的提示,表明我必须使用 CDK 的一些指令,但没有示例如何使用。

所以我有问题。

  1. 如何检测 Material Tab 中的 scoll 事件以使返回顶部按钮再次淡入?
  2. 如何以编程方式在“ Material ”选项卡内滚动回顶部?

最佳答案

我自己找到了解决方案。这实际上是我在发帖之前尝试采用的方式。我必须使用 cdkScrollable 指令。

现在我知道怎么做了。您必须在每个 MatTab 内显示的组件周围放置一个 div。然后您必须将 cdkScrollable 指令附加到这些 div。然后您可以使用 TS 代码中的 ScrollDispatcher 捕获滚动事件。

最后看起来像这样:

我的BodyComponentHTML

<div id="body.component.container" style="margin-top: 62px;">
    <mat-tab-group [(selectedIndex)]="selectedMatTabIndex">
        <mat-tab>
            <ng-template matTabLabel>
                <span style="font-family: 'Arial Narrow', monospace; font-size: 16px; font-weight: bold;">Tab1</span>
            </ng-template>
            
            <div cdkScrollable>
                <app-content-component-001></app-content-component-001>
            </div>
            
        </mat-tab>
    
        <mat-tab>
            <ng-template matTabLabel>
                <span style="font-family: 'Arial Narrow', monospace; font-size: 16px; font-weight: bold;">Tab2</span>
            </ng-template>
            
            <div cdkScrollable>
                <app-content-component-002></app-content-component-002>
            </div>
            
        </mat-tab>
    </mat-tab-group>
</div>

<app-back-to-top
        [scrollingNativeElement]="scrollingNativeElement">
</app-back-to-top>

我的BodyComponentTS(仅重要的代码行)

import { CdkScrollable, ScrollDispatcher } from '@angular/cdk/overlay';

scrollingNativeElement: HTMLElement;

constructor(public scrollDispatcher: ScrollDispatcher){}

ngOnInit(): void {
    this.scrollDispatcher.scrolled().subscribe((data: CdkScrollable) => {
            this.scrollingNativeElement = data.getElementRef().nativeElement;
    });
}

我的BackToTopButtonComponentTS

import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { animate, state, style, transition, trigger } from '@angular/animations';

@Component({
    selector: 'app-back-to-top',
    templateUrl: './back-to-top.component.html',
    styleUrls: ['./back-to-top.component.css'],
    animations: [
        trigger('appearInOut', [
            state('in', style({
                'display': 'block',
                'opacity': '1'
            })),
            state('out', style({
                'display': 'none',
                'opacity': '0'
            })),
            transition('in => out', animate('400ms ease-in-out')),
            transition('out => in', animate('400ms ease-in-out'))
        ]),
    ]
})

export class BackToTopComponent implements OnInit, OnDestroy, OnChanges {
    animationState = 'out';

    @Input() scrollingNativeElement: HTMLElement;


    ngOnInit(): void
    {
    }

    ngOnDestroy(): void
    {
    }

    ngOnChanges(changes: SimpleChanges): void
    {
        if (changes['scrollingNativeElement'].currentValue)
        {
            this.animationState = (this.scrollingNativeElement.scrollTop > 0) ? 'in' : 'out';
        }
    }

    scrollToTop(): void
    {
        this.scrollingNativeElement.scrollTo(0, 0);
    }
}

我的BackToTopButtonComponentHTML

<button mat-fab type="button"
        id="BT1000"
        aria-label="Back to top of the page"
        class="back-to-top-button"
        [@appearInOut]="animationState"
        (click)="scrollToTop()"
        matTooltip="scroll to top">
    <mat-icon class="back-to-top-mat-icon" svgIcon="YOUR ICON GOES HERE"></mat-icon>
</button>

我的BackToTopButtonComponentCSS

.back-to-top-button {
  position: fixed;
  right: 40px;
  bottom: 40px;
  border: 0;
  outline: none;
  color: black;
  background: #f2f2f2;
  text-decoration: none;
  cursor: pointer;
  z-index: 9999;
}

.back-to-top-mat-icon {
  transform: scale(1.5);
}

关于angular - 如何检测 Angular Material 选项卡内的滚动事件以及如何以编程方式滚动回顶部?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66269273/

相关文章:

angular - 在响应式表单中初始化 FormGroup 的位置?

angular - 命名空间 node_module/@angular/core/core 没有导出成员 ɵɵFactoryDe​​claration | ɵɵInjectorDeclaration | ɵɵNgModuleDeclaration

html - 使用 ngModelChange 更改样式

css - 更改大纲输入字段中的背景颜色

angular - 在地址栏上键入的任何 url 都会导航回 Angular 4 中的根 url

Angular Material 表 - 摘要行 - 解决方法( Material 2)

html - 在 mat-vertical-stepper 中禁用 mat-step

Angular 更新 10.2 到 11

angular - 在 Angular 5 应用程序中的 Chrome 和 Firefox 中出现 aw snap 错误

angular - 如何测试使用 Angular 6+ 调用可观察对象的拦截器?