背景:
实现原理为 在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