无限滚动已经存在了一段时间了。 基本思想:当您滚动时,新内容会在底部加载,从而创建看似无穷无尽的滚动。 实现起来很简单,但如果没有仔细规划,性能就会受到影响。 经过几次内容重新获取后,您可能会拥有数百个 DOM 元素,其中许多元素是不可见的。 幸运的是,存在一些模式可以缓解这种情况,我们将使用 Angular 来探索一种模式。
这是我们想要避免的。
虚拟滚动在任何时候仅渲染大列表的子集——与无限滚动不同。 它非常适合一次性渲染所有内容效率低下的大型数据集。 仅渲染可见(和近乎可见)的项目;当用户滚动时,项目会动态交换。 这显着减少了 DOM 元素,从而提高了性能。
虚拟滚动通过创建与视口高度匹配的容器来工作。 只有可见项目(加上缓冲区)才会在此容器中以特定的滚动深度呈现,并通过 CSS 进行管理。 滚动更新容器,显示新项目并删除视图之外的项目,调整滚动深度。 将此与无限滚动相结合,创建一个几乎无限的列表,而不会造成性能损失。
下面的示例显示了包含数千个项目的列表,但一次最多渲染 8 个。 滚动会调整 CSS 滚动高度,产生列表更长的错觉。
让我们构建一个 Angular 应用程序,从 Reddit 的分页 API 获取媒体并将其显示在虚拟滚动列表中。 它将包括一个用于子 Reddit 选择的搜索栏和一个过滤器。 向下滚动可加载更多内容。 我们的关键要求:
我们将使用 @angular/cdk
包(包含 Virtual Scroller 组件)。使用npm i @angular/cdk
安装它。
虽然此示例使用 Angular,但类似的模式也适用于 React、Vue 或 vanilla JavaScript。 此处提供了说明基本原理的基本演示。
首先,我们创建一个服务,使用 Angular 的 HttpClient
和 RxJS Observables 从 Reddit API 获取内容来管理 subreddit 名称和过滤器。 (为简洁起见,省略了一些代码;完整的实现在这里)。
<code class="language-typescript">// ... (Omitted for brevity) ...</code>
内容获取方法在数据请求期间跟踪特定属性。 page
属性被添加到查询字符串中,以确保在最后一项之后获取新内容。 我们还过滤掉 NSFW 内容和缺少帖子提示的项目。这可确保仅显示预期的内容。
<code class="language-typescript">// ... (Omitted for brevity) ...</code>
query$
observable(之前被省略)在获取内容之前合并不同的 observable 流。 scan
运算符结合了先前和当前的流结果,构建跨多个页面的大型数据数组。
这允许广泛滚动;只有 subreddit 名称或过滤器更改才会触发完整的重新获取。 nextPage
是 query$
的属性,存储当前集合中的最后一个项目 ID,用于确定在接近虚拟滚动条底部时要获取的下一页。
<code class="language-typescript">// ... (Omitted for brevity) ...</code>
RxJS 的强大之处在于组合和操作数据流。这使我们能够在业务逻辑到达组件之前对其进行处理,从而使组件保持清洁和可重用。
接下来,我们使用 Angular 的 CdkVirtualScrollViewport
设置组件来显示内容。 一个方法处理视口底部附近的滚动,通过 subRedditPage$
observable 获取下一页。
<code class="language-typescript">// ... (Omitted for brevity) ...</code>
模板使用异步管道订阅query$
。 注意:随着内容高度可变,虚拟滚动条变得更加复杂;为了提高性能,建议使用一致的物品高度。
<code class="language-html">// ... (Omitted for brevity) ...</code>
当用户接近底部时,onScroll
方法会获取更多内容。它使用 nextPage
ID(来自 query$
)并发送到 subRedditPage$
,触发下一个 API 调用并通过 query$
更新列表。
<code class="language-typescript">// ... (Omitted for brevity) ...</code>
搜索栏和选项卡控件也集成在一起(下面的简化示例)。
<code class="language-typescript">// ... (Omitted for brevity) ...</code>
这会创建一个几乎无限的滚动条。 您可以在此处进行测试。 Reddit 的 API 有速率限制;你可能会在测试过程中碰到它们。 有关更多详细信息,包括其他功能,请参阅 GitHub 存储库此处。
以上是使用 Angular 实现几乎无限滚动的详细内容。更多信息请关注PHP中文网其他相关文章!