【发布时间】:2018-05-25 16:14:29
【问题描述】:
我正在使用 ag-grid 无限行模型,并注意到当我到达一个块的末尾时,会发生下一个块的获取。有没有一种方法可以在用户滚动到该点之前触发此获取多行,以便视图看起来更加无缝?例如在到达块末尾之前预缓存块?
【问题讨论】:
标签: javascript ag-grid
我正在使用 ag-grid 无限行模型,并注意到当我到达一个块的末尾时,会发生下一个块的获取。有没有一种方法可以在用户滚动到该点之前触发此获取多行,以便视图看起来更加无缝?例如在到达块末尾之前预缓存块?
【问题讨论】:
标签: javascript ag-grid
是的,这是可能的。我们已经实现了相同的功能,尽管我们主要关心的不是预取行,而是使用 Ag-Grid-For-Angular 实现干净的 Redux。虽然它很hacky,所以你已经被警告过。另请注意,我已经删除了所有特定于 Angular 的部分,因此理论上该解决方案也应该适用于本机 JS/TS(在 RXSJ 的帮助下)。但我自己没有测试过。请报告您是否成功。现在让我们开始吧:
在gridOptions-object中,你可以设置:
onViewportChanged: (event: ViewportChangedEvent) => {
// here you have access to event.firstRow and event.lastRow
// On initialization, firstRow is 0 and lastRow -1
}
但这并不是你认为的那样。 ViewportChangedEvent 不代表屏幕上当前可见元素的块,而是最后加载的块(可能尚未在视口中的元素)。但是您仍然需要此信息来计算已获取的内容与您现在在屏幕上的位置之间的距离。
对于第二条需要的信息(例如您现在在哪里),您确实可以访问另一种方法,但这是我从 AgGrid 创始人 Niall Crosby 在 GitHub 上的评论中得到的,它不在官方文档而不是在 AgGrid 的 Typescript 界面中:
首先你需要定义一个字段
private _onAgGridBodyScroll$ = new Subject<BodyScrollEvent>();
因为滚动每秒会发生多次,并且您希望使用 debounceTime 仅处理最大数量的滚动事件。然后你需要将实际的视口事件推送到 Observable/Subject 中。所以在定义了gridOptions之后,做:
(this.gridOptions as any).onBodyScroll = ((bodyScrollEvent: BodyScrollEvent) =>
this._onAgGridBodyScroll$.next(bodyScrollEvent));
正如我提到的,onBodyScroll 没有正式记录,它也不在GridOptions 接口中,这就是我为什么要进行演员as any
this._onAgGridBodyScroll$
.takeUntil(this._destroy$)
.debounceTime(200)
.subscribe(() => {
const allRows: HTMLElement[] = this._hostEl.nativeElement.getElementsByClassName('ag-row');
if (allRows.length < 1) {
return;
}
// aggrids viewport-rows can be inserted in a wrong/random order in the DOM, but they always have the right index-attribute:
let biggestIndexInViewport: number = Number(allRows[0].getAttribute('row-index'));
for (let i = 1; i < allRows.length; i++) {
const itemIndexByAttr: number = Number(allRows[i].getAttribute('row-index'));
if (itemIndexByAttr > biggestIndexInViewport) {
biggestIndexInViewport = itemIndexByAttr;
}
}
// so now you have the reference to the last visible row
// note that by flipping the > you can also find out the first visible row
// so when you destroy aggrid and reinitialize it again
// with all the fetched items you have in your redux-store,
// you can scroll-to-top to the same row where you have been before
});
现在,拥有对最后一个获取块的引用以及最后一个可见项,您可以自己控制请求。只需设置这两个参数之间的距离并调用您的 httpClient 并更新您的项目数组。现在唯一剩下的就是在网格模型中设置获取的项目:
// do this in onGridReady():
this.gridOptions.api.setDatasource({
rowCount: null, // behave as infinite scroll
getRows: (params: IGetRowsParams) => this.onGetRows(params)
} as IDatasource);
// and define:
private onGetRows(params: IGetRowsParams): void {
this.artikelArray$
.takeUntil(this._destroy$)
.filter((myItems: MyItems[]) => (!!myItems[params.startRow]))
// do not check for endrow because request is always of static size, but response might be smaller
.take(1) // unsubscribe after first handled value
.subscribe(rowsToDisplay => {
const limit: number = params.endRow >= this._totalCount ? this._totalCount : -1; // the smaller limit or none at all
// in case you have new information concerning maximum size:
params.successCallback(rowsToDisplay, limit);
});
}
请注意,_totalCount 是您可以为分块请求获得的最大行数。您可以从后端查询中获取此信息,例如 Lucene/ElasticSearch。您还可以将限制设置为 -1,在这种情况下,您始终可以向下滚动,但永远不会加载行。
还要注意,当你自己取东西时,第一个块需要手动取,因为this._onAgGridBodyScroll$ 只会在视口中已经有一些数据的情况下被触发并导致后续的取。这是我提到的特定于 Angular 的部分(在 Angular 中,您可以在初始化生命周期挂钩“OnInit”中执行此操作)。
就是这样!希望能帮助到你。实际上我正在写一篇关于这个的博客文章,里面有图片和东西;完成后我会在这里添加一个链接。如果您有任何建议,请发表评论。
【讨论】: