仿Uber Eats的Angular网页端联动滚动横向分类菜单实现
Angular实现滚动联动分类菜单(替代Bootstrap ScrollSpy)
核心思路
放弃Bootstrap ScrollSpy,直接通过监听窗口滚动事件,计算各分类内容区块的位置,对比当前滚动高度来自动切换菜单的激活状态,逻辑更可控,适配Angular环境。
具体实现步骤
1. 定义分类数据
在组件类里先声明分类列表和当前激活的分类ID:
categories = [ { id: 'electronics', name: '电子产品' }, { id: 'clothing', name: '服饰' }, { id: 'home', name: '家居' } ]; activeCategoryId = 'electronics';
2. 编写页面模板
横向滚动菜单用flex+overflow-x:auto实现,内容区每个分类对应带唯一ID的区块:
<!-- 横向滚动分类菜单 --> <div class="category-scroll"> <div *ngFor="let category of categories" class="category-item" [class.active]="activeCategoryId === category.id" (click)="scrollToCategory(category.id)" > {{ category.name }} </div> </div> <!-- 分类内容区 --> <div class="content-container"> <div id="electronics" class="category-section"> <!-- 电子产品分类内容 --> </div> <div id="clothing" class="category-section"> <!-- 服饰分类内容 --> </div> <div id="home" class="category-section"> <!-- 家居分类内容 --> </div> </div>
3. 设置基础样式
给菜单和内容区块添加样式,确保横向滚动和视觉区分:
.category-scroll { display: flex; overflow-x: auto; padding: 1rem 0; border-bottom: 1px solid #eee; /* 隐藏滚动条(可选) */ scrollbar-width: none; -ms-overflow-style: none; } .category-scroll::-webkit-scrollbar { display: none; } .category-item { padding: 0.5rem 1rem; margin-right: 1rem; white-space: nowrap; cursor: pointer; transition: color 0.2s; } .category-item.active { color: #007bff; border-bottom: 2px solid #007bff; } .content-container { padding: 1rem 0; } .category-section { min-height: 600px; /* 给每个区块设置最小高度,方便测试滚动 */ margin-bottom: 2rem; }
4. 实现滚动联动逻辑
在组件里监听滚动事件,计算区块位置并更新激活状态,同时添加点击菜单滚动到对应区块的功能:
import { Component, OnInit, OnDestroy } from '@angular/core'; import { fromEvent, Subscription } from 'rxjs'; import { debounceTime } from 'rxjs/operators'; @Component({ selector: 'app-category-scroll', templateUrl: './category-scroll.component.html', styleUrls: ['./category-scroll.component.css'] }) export class CategoryScrollComponent implements OnInit, OnDestroy { categories = [ { id: 'electronics', name: '电子产品' }, { id: 'clothing', name: '服饰' }, { id: 'home', name: '家居' } ]; activeCategoryId = 'electronics'; scrollSubscription!: Subscription; ngOnInit(): void { // 监听滚动事件,加防抖避免频繁触发 this.scrollSubscription = fromEvent(window, 'scroll') .pipe(debounceTime(100)) .subscribe(() => this.updateActiveCategory()); } ngOnDestroy(): void { // 销毁订阅,防止内存泄漏 this.scrollSubscription.unsubscribe(); } updateActiveCategory(): void { // 加100px偏移量,让菜单切换时机更贴合视觉感受 const scrollTop = window.scrollY + 100; // 从后往前遍历,确保优先匹配当前可见的最上方区块 for (let i = this.categories.length - 1; i >= 0; i--) { const section = document.getElementById(this.categories[i].id); if (section) { const sectionTop = section.offsetTop; if (scrollTop >= sectionTop) { this.activeCategoryId = this.categories[i].id; break; } } } } scrollToCategory(categoryId: string): void { const section = document.getElementById(categoryId); if (section) { // 平滑滚动到对应区块顶部 section.scrollIntoView({ behavior: 'smooth', block: 'start' }); } } }
关键细节说明
- 防抖处理:用
debounceTime(100)降低滚动事件触发频率,避免性能损耗。 - 偏移量调整:
scrollTop + 100可根据实际布局调整,让菜单切换时机更自然。 - 内存泄漏预防:组件销毁时必须取消滚动事件订阅。
- 平滑滚动:点击菜单时用
scrollIntoView实现流畅的滚动效果。
内容的提问来源于stack exchange,提问作者Akitha Fonseka
相关产品推荐
相关产品推荐

