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

如何在Angular 17中实现鼠标滚轮触发的区块间平滑滚动?

Angular 17 全屏区块滚轮平滑切换实现方案

针对你的需求,以下是对现有代码的优化方案,解决滚动偏移、超时不准确等问题,完美实现区块间平滑切换且滚动过程禁用滚轮操作:

改进后的组件代码

import { Component, HostListener, OnInit } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  sections: string[] = ['home', 'about', 'skills', 'contact'];
  currentSectionIndex = 0;
  isScrolling = false;
  private scrollEndListener?: () => void;

  ngOnInit(): void {
    // 页面加载时默认定位到第一个区块
    this.scrollToSection(this.sections[this.currentSectionIndex], false);
  }

  @HostListener('window:wheel', ['$event'])
  onScroll(event: WheelEvent) {
    if (this.isScrolling) {
      event.preventDefault();
      return;
    }

    // 阻止原生滚动行为,避免页面偏移
    event.preventDefault();

    event.deltaY > 0 ? this.nextSection() : this.previousSection();
  }

  nextSection() {
    if (this.currentSectionIndex < this.sections.length - 1) {
      this.currentSectionIndex++;
      this.scrollToSection(this.sections[this.currentSectionIndex]);
    }
  }

  previousSection() {
    if (this.currentSectionIndex > 0) {
      this.currentSectionIndex--;
      this.scrollToSection(this.sections[this.currentSectionIndex]);
    }
  }

  scrollToSection(sectionId: string, smooth = true) {
    this.isScrolling = true;
    const element = document.getElementById(sectionId);
    if (!element) {
      this.isScrolling = false;
      return;
    }

    // 清理之前的滚动结束监听,防止重复绑定
    if (this.scrollEndListener) {
      window.removeEventListener('scrollend', this.scrollEndListener);
    }

    // 绑定滚动结束事件,准确恢复滚轮功能
    this.scrollEndListener = () => {
      this.isScrolling = false;
      window.removeEventListener('scrollend', this.scrollEndListener!);
      this.scrollEndListener = undefined;
    };
    window.addEventListener('scrollend', this.scrollEndListener);

    // 执行平滑滚动,确保区块顶部对齐视口
    element.scrollIntoView({
      behavior: smooth ? 'smooth' : 'auto',
      block: 'start'
    });
  }

  // 可选:配合菜单跳转同步区块索引
  navigateToSection(sectionId: string) {
    const index = this.sections.indexOf(sectionId);
    if (index !== -1 && index !== this.currentSectionIndex) {
      this.currentSectionIndex = index;
      this.scrollToSection(sectionId);
    }
  }
}

配套CSS设置

在app.component.css中添加以下样式,确保区块全屏且页面无默认滚动:

body, html {
  margin: 0;
  padding: 0;
  overflow: hidden; /* 禁用原生页面滚动 */
}

app-home, app-about, app-skills, app-contact {
  display: block;
  height: 100vh;
  width: 100%;
}

关键优化点说明

  • 阻止原生滚动:在滚轮事件中调用event.preventDefault(),彻底避免原生滚动导致的页面偏移,完全由自定义逻辑控制区块切换。
  • 滚动结束精准监听:用scrollend事件替代固定超时,滚动完成后自动恢复滚轮功能,比固定时间更准确,不会出现提前恢复或恢复过晚的问题。
  • 区块对齐优化:scrollIntoView添加block: 'start'参数,确保区块顶部严格对齐视口,避免滚动位置偏差。
  • 重复监听清理:每次滚动前移除之前的scrollend监听,防止多次绑定导致的逻辑混乱。
  • 初始化定位:页面加载时自动定位到第一个区块,确保初始状态正确。

注意事项

  • 确保每个区块组件的根元素为块级元素,且已设置height: 100vh,否则滚动定位可能失效。
  • 如果菜单有跳转需求,可调用navigateToSection方法,同步区块索引,保证滚轮逻辑与菜单跳转的一致性。
  • 若使用SSR,建议将初始化滚动逻辑移至AfterViewInit钩子中,避免DOM未加载完成的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 16:03:20