javascript - ReactJS:建模双向无限滚动

标签 javascript html infinite-scroll reactjs

我们的应用程序使用无限滚动来导航大量不同项目的列表。有一些皱纹:

  • 我们的用户通常有一个包含 10,000 个项目的列表并且需要滚动浏览 3k+。
  • 这些都是丰富的项目,因此在浏览器性能变得 Not Acceptable 之前,我们只能在 DOM 中拥有几百个项目。
  • 元素的高度各不相同。
  • 这些项目可能包含图像,我们允许用户跳转到特定日期。这很棘手,因为用户可以跳转到列表中我们需要在视口(viewport)上方加载图像的点,这会在加载内容时将内容向下推。未能处理这意味着用户可能会跳转到某个日期,但随后会转到更早的日期。

已知的、不完整的解决方案:

  • ( react-infinite-scroll ) - 这只是一个简单的“当我们到达底部时加载更多”组件。它不会剔除任何 DOM,因此它会在数千个项目上消失。

  • ( Scroll Position with React ) - 显示在顶部插入时如何存储和恢复滚动位置在底部插入,但不是同时插入.

我不是在寻找完整解决方案的代码(尽管那会很棒。)相反,我在寻找“React 方式”来模拟这种情况。滚动位置状态与否?我应该跟踪什么状态才能保留我在列表中的位置?我需要保持什么状态才能在靠近渲染内容的底部或顶部滚动时触发新的渲染?

最佳答案

这是无限表格和无限滚动场景的混合体。我为此找到的最佳抽象如下:

概览

制作 <List>包含所有 子元素的数组的组件。因为我们不渲染它们,所以分配它们并丢弃它们真的很便宜。如果 10k 分配太大,您可以改为传递一个采用范围并返回元素的函数。

<List>
  {thousandelements.map(function() { return <Element /> })}
</List>

你的 List组件跟踪滚动位置是什么,并且只渲染 View 中的子项。它在开头添加了一个大的空 div 来伪造之前未呈现的项目。

现在,有趣的部分是一旦 Element组件被渲染,你测量它的高度并将它存储在你的 List 中.这使您可以计算间隔物的高度并知道应在 View 中显示多少个元素。

图片

您是说当加载图像时,它们会使所有内容“跳”下来。解决方案是在您的 img 标签中设置图像尺寸:<img src="..." width="100" height="58" /> .这样浏览器就不必等到下载它才知道它要显示的大小。这需要一些基础设施,但确实值得。

如果不能提前知道尺寸,那就加onload收听您的图像并在加载图像时测量其显示尺寸并更新存储的行高并补偿滚动位置。

在随机元素处跳跃

如果您需要跳转到列表中的随机元素,这将需要一些滚动位置技巧,因为您不知道其间元素的大小。我建议您做的是对您已经计算出的元素高度进行平均,然后跳转到最后已知高度 +(元素数 * 平均值)的滚动位置。

由于这不是精确的,因此当您返回到最后已知的正确位置时会导致问题。当发生冲突时,只需更改滚动位置即可修复它。这会稍微移动滚动条,但不会对他/她产生太大影响。

react 细节

您想提供一个 key到所有渲染的元素,以便它们在渲染中保持不变。有两种策略:(1) 只有 n 个键 (0, 1, 2, ... n),其中 n 是您可以显示和使用它们的位置模 n 的最大元素数。 (2) 每个元素有不同的键。如果所有元素都共享相似的结构,则最好使用 (1) 来重用它们的 DOM 节点。如果他们不这样做,则使用 (2)。

我只会有两个 React 状态:第一个元素的索引和显示的元素数。当前滚动位置和所有元素的高度将直接附加到 this .使用 setState 时您实际上是在进行重新渲染,这应该只在范围发生变化时发生。

这是一个 example使用我在这个答案中描述的一些技术的无限列表。这将是一些工作,但 React 绝对是实现无限列表的好方法:)

关于javascript - ReactJS:建模双向无限滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20870448/

相关文章:

javascript - 如何使用 CSS 翻转多个 div?

javascript - 将 Angular 单页应用程序导出到静态 HTML/CSS/JS

javascript - 更改时的 Angular 选择值不更新

javascript - 在 IE 中显示长时间运行 for 循环的进度条

ios - 为什么我的页面 Controller 不能无限向后滚动?

javascript - 将 div 内的 div 与 Label 对齐?

javascript - Knockout Kendo TimePicker 禁用用户文本输入

php - 如何在页面滚动时动态检索数据到div

javascript - JQuery 无限滚动 - 达到最大页面限制后为 "load more"

php - 使用history.pushState无限滚动