Angular中使用Intersection Observer API实现无限滚动

发布时间:2023年12月18日

背景:
实现原理为 在data下面加一个loading元素 如果此元素进入视窗 则调用api获取新的数据加到原来的数据里面,这时loading就会被新数据顶下去,如此循环。

<div id="dataContainer"></div>
<div id="loadingContainer"></div>

传统angular实现是使用ngAfterViewInit()生命周期,写在指令(Directive)里面,并且传出一个事件,触发时回调被监控组件里面的具体函数。

不过对于异步操作,元素可能在ngAfterViewInit被调用时还没有完成初始化而导致bug,所以用ngAfterViewChecked() 会更稳,当然也更会导致性能问题,每次变更检测它都被调用,这可能会增加应用程序的负载。

所以这里使用h5 提供的新API ——交叉观察器 API(Intersection Observer API)提供了一种异步检测目标元素与祖先元素或顶级文档的视口相交情况变化的方法。

效果如图,为了截到loading,我在增加数据的函数里面加了个等待。
在这里插入图片描述

上代码

watch-to-view.directive.ts

import { Directive, Output,EventEmitter, ElementRef } from '@angular/core';

@Directive({
  selector: '[appWatchToView]'
})
export class WatchToViewDirective {
  private observer:IntersectionObserver;
  @Output() appWatchToView = new EventEmitter<IntersectionObserverEntry>();

  constructor(public el:ElementRef) {
    this.observer = new IntersectionObserver(this.callback,{rootMargin:'100px',threshold:1,root:null});
    this.observer.observe(el.nativeElement);
   }
  public callback = (entries: IntersectionObserverEntry[]) => {
    entries.forEach((entry: IntersectionObserverEntry) => {
      if (entry.isIntersecting) {
        this.appWatchToView.emit(entry);
      }
    })
  }

}

app.component.html

<div id="dataContainer">
    <ul>
        <li class="blueBox" *ngFor="let i of data">{{i}}</li>
    </ul>
</div>
<div id="loadingContainer" class="blueBox" appWatchToView (appWatchToView)="this.loadObserver($event)">Loading more...</div>

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'Tour of Herors';
  batch:Number = 10;
  len:Number = this.batch;
  data:Array<Number>=new Array(this.batch).fill(0).map((_,i)=>i);
  loadObserver = async function (event){
    console.log(event.target);
    await new Promise(resolve => setTimeout(resolve, 1000));
    this.data.push(...new Array(this.batch).fill(0).map((_,i)=>i+this.len));
    this.len+=this.batch;
  }
}

再给个样式吧

  .blueBox{
    display: block;
    width: 100%;
    height: 100px;
    background-color: #38b1ee;
    margin-top: 5px;
    text-align: center;
    color: white;
    font-size: large;
  }

官方link: https://developer.mozilla.org/zh-CN/docs/Web/API/Intersection_Observer_API

文章来源:https://blog.csdn.net/qq_43574741/article/details/135011030
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。