根据角度虚拟滚动的官方文档 minBufferBx 和 maxBufferPx
假设我们有以下参数:itemSize = 50, minBufferPx = 100, maxBufferPx = 250。当用户滚动浏览内容时,视口检测到只剩下 90px 的缓冲区。由于这低于 minBufferPx,因此视口必须渲染更多缓冲区。它必须至少渲染足够的缓冲区才能返回到 maxBufferPx。在这种情况下,它会渲染 4 个项目(额外的 200 像素)以使总缓冲区大小达到 290 像素,回到 maxBufferPx 之上。
所以我明白,如果我的可见视口高度为 250px,那么虚拟滚动视口将呈现在 350px 和 500px 之间。因此,当我搜索无限滚动支持时,大多数教程都提供了以下代码。
const end = this.viewport.getRenderedRange().end;
const total = this.viewport.getDataLength();
console.log(`${end}, '>=', ${total}`);
if (end === total) {
this.offset.next(offset);
}
上面的代码我理解的是,如果视口渲染范围结束等于当前检索到的数据长度,那么将请求下一批数据。渲染范围结束等于 minBufferPx 和 maxBufferPx 之间的项目索引。例如,如果内容窗口高度为250px,item高度为50px,firstVisibleIndex在item index 2处,设置minBufferPx=350,maxBufferPx=350,那么根据上面的minBufferPx,渲染的范围end item至少在index处12. 所以如果 end === total,则请求下一批。
但是根据我的实现代码,实际不是这样的。
<cdk-virtual-scroll-viewport
itemSize="64" minBufferPx="64*20" maxBufferPx="64*35" (scrolledIndexChange)="scrollIndexChange($event)">
scrollIndexChange(firstVisibleIndex: number) {
if (this.previousFirstVisibleIndex < firstVisibleIndex &&
this.scrollViewPort.getDataLength() === this.scrollViewPort.getRenderedRange().end) {
this.logService.logger.debug(this.tag + 'scroll index change: request next: firstVisibleIndex:' + firstVisibleIndex + ', ',
this.scrollViewPort.getDataLength() + ', ' + this.scrollViewPort.getRenderedRange().end);
// get next batch contact list
this.getNextBatch();
}
我的内容寡妇高度是 576px,它可以在可见范围内放置 9 个项目。我监控我的滚动行为并检查下一场比赛日志的请求
scroll index change: request next: firstVisibleIndex: 26, dataLength: 35, renderedRange end: 35
scroll index change: request next: firstVisibleIndex: 54, dataLength: 63, renderedRange end: 63
scroll index change: request next: firstVisibleIndex: 85, dataLength: 94, renderedRange end: 94
scroll index change: request next: firstVisibleIndex: 118, dataLength: 127, renderedRange end: 127
我发现 minBufferPx、maxBufferPx 没有按预期工作。FirstVisibleIndex 和 renderRange end 总是相差 9 个项目,即可见窗口高度。所以按照上面的实现,无限滚动的体验并不好。它只在最后滚动到达时请求下一批。
所以我尝试修改我的代码,如下所示,以测试更好的滚动体验。
if (this.previousFirstVisibleIndex < firstVisibleIndex && firstVisibleIndex + 20 >= this.scrollViewPort.getDataLength()) {
this.logService.logger.debug(this.tag + 'scroll index change: request next: firstVisibleIndex:' + firstVisibleIndex + ', ',
this.scrollViewPort.getDataLength() + ', ' + this.scrollViewPort.getRenderedRange().end);
this.getNextBatch()
}
上面的代码有点像保留 11 个项目的缓冲区,并请求下一批。上面的方法也不好,因为我使用的是常数 20 数字。如果内容窗口更改为放置 21 个项目,则此代码将出现问题。
请问我对minbufferPx和maxBufferPx的理解有没有错?它没有反映在 getRenderedRange().end 中吗?