返回

打造你的无限滚动加载指令:Angular 与 RxJS Observables 强强联手

前端

使用 Angular 指令实现无限滚动加载:分步指南

简介

无限滚动加载是一种广泛使用的技术,它允许用户在页面上向下滚动时自动加载更多内容。本文将指导您使用 Angular 指令一步一步实现无限滚动加载功能。

准备工作

首先,使用 Angular CLI 创建一个新项目:

ng new infinite-scroll-directive

然后,安装必要的依赖项:

npm install rxjs@6.x --save

创建指令

下一步是创建一个 Angular 指令来处理无限滚动加载。我们称之为 infiniteScroll

// src/app/infinite-scroll.directive.ts
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
import { fromEvent } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';

@Directive({
  selector: '[appInfiniteScroll]'
})
export class InfiniteScrollDirective {

  @Input() public threshold: number;
  private scrollEvent$;

  constructor(private el: ElementRef) { }

  ngOnInit() {
    this.scrollEvent$ = fromEvent(this.el.nativeElement, 'scroll');
  }

  @HostListener('window:scroll', [])
  onScroll() {
    if (this.scrollEvent$) {
      this.scrollEvent$.pipe(
        debounceTime(200),
        distinctUntilChanged(),
        switchMap(() => {
          const currentScrollPosition = window.scrollY + window.innerHeight;
          const contentHeight = this.el.nativeElement.scrollHeight;
          const remaining = contentHeight - currentScrollPosition;

          if (remaining < this.threshold) {
            // 触发事件来获取更多数据
            return this.onScrollEnd.emit();
          }
        })
      ).subscribe();
    }
  }

  @Output() public onScrollEnd: EventEmitter<any> = new EventEmitter();
}

使用指令

现在,您可以在组件中使用此指令。首先,在 app.component.html 中添加一个元素并附加 appInfiniteScroll 指令:

<div class="container" appInfiniteScroll [threshold]="200" (onScrollEnd)="onScrollEnd()">
  <ul>
    <li *ngFor="let item of items">
      {{ item }}
    </li>
  </ul>
</div>

接下来,在 app.component.ts 中处理 onScrollEnd() 事件:

// src/app/app.component.ts
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  public items: Array<string> = [];

  constructor(private http: HttpClient) { }

  ngOnInit() {
    this.getNews();
  }

  public onScrollEnd() {
    this.getNews();
  }

  private getNews() {
    this.http.get('https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty')
      .pipe(map((res: any) => res.slice(0, 10)))
      .subscribe((res: any) => {
        const observables = [];

        res.forEach((id: number) => {
          observables.push(this.http.get(`https://hacker-news.firebaseio.com/v0/item/${id}.json`));
        });

        forkJoin(observables).subscribe((results: any) => {
          this.items = this.items.concat(results.map((result: any) => result.title));
        });
      });
  }
}

运行项目

运行项目以测试无限滚动加载功能:

ng serve

当页面加载时,您会看到一个列表,其中包含前 10 条 HackerNews 头条新闻。当您向下滚动页面时,您会看到更多新闻被加载到列表中。

常见问题解答

1. 如何自定义阈值距离?

通过设置 threshold 输入属性,可以自定义当剩下多少内容时触发加载更多数据的阈值距离。

2. 如何处理加载错误?

onScrollEnd() 方法中,您可以添加错误处理逻辑来处理加载过程中的任何错误。

3. 如何取消订阅滚动事件?

在组件的 ngOnDestroy 生命周期钩子中,取消订阅 scrollEvent$ 以释放资源。

4. 是否可以使用其他库来实现无限滚动加载?

是的,有许多库可用于实现无限滚动加载,例如 ngx-infinite-scroll。

5. 如何对无限滚动列表进行分页?

可以使用服务器端分页或客户端分页技术对无限滚动列表进行分页。

结论

使用 Angular 指令实现无限滚动加载是一个简单而强大的技术,它可以增强用户体验。遵循本文中的步骤,您可以轻松地将此功能集成到您的 Angular 应用程序中。