You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular @HostListener监听滚动事件无法获取正确滚动值问题

Angular Material mat-drawer 容器滚动位置获取问题

问题复现代码

在app.component.html中编写如下全局侧边栏布局结构:

<app-header *ngIf="navbarTop"></app-header>

<mat-drawer-container id="drawer-container">

    <mat-drawer mode="over" id="side-drawer" [opened]="isOpen">
        <div>
            <!-- Sidenav content -->
        </div>
    </mat-drawer>

    <!-- Main content of the site -->
    <mat-drawer-content id="scroller" (scroll)="scrollHandler($event)">
        <main class="container">
            <router-outlet></router-outlet>
        </main>
    </mat-drawer-content>

</mat-drawer-container>

<app-header *ngIf="!navbarTop"></app-header>

该结构通过全局mat-drawer实现侧边导航,确保所有页面都可访问侧边菜单,站点主内容区域的mat-drawer-content中放置router-outlet承载路由页面。
尝试过将(scroll)事件绑定在mat-drawer、main标签以及router-outlet上,确认绑定在mat-drawer-content上是最优选择。但.ts文件中编写如下滚动监听逻辑时出现异常:

@HostListener('window:scroll', ['$event']) 
scrollHandler(e) {
  console.log("scrolled");
  console.log(window.scrollY);
  console.log(document.body.scrollTop);
}

运行时滚动事件可以正常触发,但window.scrollY、document.body.scrollTop的打印结果始终为0,无法获取正确的scrollY/offsetY/scrollTop等滚动位置数值。

问题原因

mat-drawer组件默认会为根节点<html>、<body>添加height: 100%; overflow: hidden样式,禁用页面本身的滚动条,所有主内容区的滚动行为全部由内部的mat-drawer-content元素承接。此时滚动的容器不是window也不是body,因此读取window.scrollY、document.body.scrollTop永远返回0。
同时模板上已经给mat-drawer-content绑定了(scroll)事件,额外用@HostListener监听window滚动属于冗余逻辑,还可能导致重复触发。

解决方案

方法1:直接从滚动事件对象获取(推荐)

删除@HostListener('window:scroll')装饰器,直接从滚动事件的目标元素上读取scrollTop值即可:

scrollHandler(e: Event) {
  const scrollContainer = e.target as HTMLElement;
  // 实际滚动位置
  const scrollTop = scrollContainer.scrollTop;
  console.log("滚动位置:", scrollTop);
  // 其他滚动相关属性可按需获取
  // scrollContainer.scrollHeight 内容总高度
  // scrollContainer.clientHeight 可视区域高度
}

方法2:通过组件引用获取(非事件场景使用)

如果需要在滚动事件之外的逻辑里获取滚动位置,可以通过模板变量+ViewChild拿到mat-drawer-content的实例再读取属性:

  1. 首先给模板里的mat-drawer-content添加模板引用变量:
<mat-drawer-content #scroller id="scroller" (scroll)="scrollHandler($event)">
  1. 在组件类中通过ViewChild获取组件实例,需要时读取原生元素的滚动属性:
import { Component, ViewChild } from '@angular/core';
import { MatDrawerContent } from '@angular/material/sidenav';

@Component({
  // 组件元配置
})
export class AppComponent {
  @ViewChild('scroller') private scroller: MatDrawerContent;

  // 任意需要获取滚动位置的方法中调用
  getCurrentScrollTop() {
    const scrollContainer = this.scroller.getElementRef().nativeElement;
    return scrollContainer.scrollTop;
  }
}

内容的提问来源于stack exchange,提问作者hego64

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 08:24:15