忏悔:我还没有在我当前的应用程序上实现分页,但这就是我将如何处理它。
在我之前的回答中,我解释了如何在doc
受 VuexFire 或 VueFire 绑定的状态数组的每个元素中保留对 Firestore 对象的引用。在下面的解决方案 #1 中,我们使用这些 doc 对象来实现 Firestore 推荐的基于游标的查询结果集分页,使用startAfter(doc)
查询条件而不是更慢更昂贵的offset
子句。
请记住,由于我们使用的是 Vuexfire/Vuefire,我们说我们希望订阅对查询的实时更改,因此我们的绑定查询将准确定义绑定数组中的最终结果。
解决方案#1。向前/向后分页加载并显示整个数据集的水平切片(我们的绑定数组保持相同的大小 = 页面大小)。这不是您所要求的,但考虑到Cons
其他解决方案,这可能是首选解决方案。
- 优点:服务器:对于大型数据集,此分页查询将以最少的成本和延迟执行。
- 优点:客户端:保持较小的内存占用,并且渲染速度最快。
- 缺点:分页可能不会像滚动一样。UI 可能只有按钮可以前进/后退。
- Page Forward :从状态数组的最后一个元素中获取
doc
对象,并将条件应用于我们更新的视图查询,将我们的数组绑定到下一页。startAfter(doc)
- 向后翻页:再难一点!从绑定状态数组的第一个元素中获取
doc
对象。使用 startAfter(doc)、limit (1)、offset(pagesize-1) 和反向排序顺序运行我们的页面查询。结果是上一页的起始文档(pageDoc)。现在使用and forward sort order 和 limit(pageSize) 重新绑定状态数组(与 Page Forward 相同的查询,但使用 doc = pageDoc)。startAfter(pageDoc)
注意:在一般情况下,我认为我们不能只保留以前页面的 pageDoc 值(以避免我们的反向查询),因为我们将其视为“实时”更新过滤列表,因此项目数自从我们向下滚动以来,仍然保留在以前的页面中可能已经发生了根本性的变化。您的特定应用程序可能不会期望这种变化率,因此保留过去的 pageDoc 值可能会更聪明。
解决方案#2。向前分页,扩展查询结果和绑定数组的大小。
优点:用户体验感觉就像正常滚动,因为我们的数组增长了。
优点:不需要使用serializer
技巧,因为我们没有使用startAfter()
或endBefore()
缺点:服务器:每次重新绑定到新页面时,您都会从 Firestore 将整个阵列重新加载到新页面,然后获取不断增长的阵列的实时更新。所有这些文档阅读都可能变得昂贵!
缺点:客户端:当您向前翻页时,渲染可能会变慢 - 尽管影子 DOM 可能会解决这个问题。UI 可能会在您每次重新加载时闪烁,因此需要更多的 UI 魔术技巧(延迟渲染直到数组完全更新)。
优点:如果我们使用无限滚动功能,可能会很好用。我得测试一下。
Page Forward:添加pageSize
到我们的查询限制并重新绑定 - 这将重新查询 Firestore 并重新加载所有内容。
Page Backward:从我们的查询限制中减去pageSize
并重新绑定/重新加载(或不重新加载!)。可能还需要更新我们的滚动位置。
解决方案#3。解决方案#1 和#2 的混合。我们可以选择使用实时 Vuexfire/Vuefire 绑定来处理我们的查询/集合的一部分(如解决方案 #1),并使用计算函数将它与包含我们已经加载的数据页面的数组连接起来。
- 优点:降低了 Firestore 查询成本和查询延迟,但现在具有平滑的滚动外观和感觉,因此可以使用无限滚动 UI。给我一杯Koolaid!
- 缺点:我们将不得不尝试跟踪我们数组的哪个部分被显示,并使该部分绑定并实时更新。
- Page Forward/Backward:与解决方案#1 相同的处理方式,用于绑定当前数据页,不同之处在于我们现在必须将前一页数据复制到我们的非实时数据数组中,并将一个小的计算函数编码到
concat()
两个数组中,然后将 UI 列表绑定到此计算数组。
解决方案#3a我们可以作弊,而不是真正保留不可见的早期数据页面。相反,我们只是用相同高度的(或类似的)替换每个页面div
;)所以我们的滚动看起来我们已经向下滚动了相同的距离。当我们向后滚动时,我们需要删除我们偷偷摸摸的前一页div
并将其替换为新绑定的数据。如果您正在使用无限滚动,为了使滚动 UX 美观流畅,您需要在前面或后面预加载一个额外的页面,以便在滚动到分页符之前它已经加载好。一些无限滚动 API 不支持这一点。
解决方案 #1 和 #3 可能需要 VueFire 的Cookbook PR或一个不错的 MIT'd / NPM 库。有接盘侠吗?