大多数web应用程序背后的思想都是从数据库中获取数据,并以最好的方式将数据呈现给用户。当我们处理数据时,有时最好的呈现方法就是创建一个列表。
根据数据量及其内容,我们可以决定一次显示所有内容(很少),或者只显示一个更大数据集的特定部分(更有可能)。只显示部分现有数据的主要原因是,我们希望尽可能保持应用程序的性能,并避免加载或显示不必要的数据。
如果我们决定以“chunks(块)”的形式显示数据,那么我们需要一种方法来导航该数据集合。对一组数据进行导航的最常见的两种方法是:
第一个是分页,这是一种将数据集分割为特定数量的页面的技术,它可以避免用户被一个页面上的数据量淹没,并允许用户一次查看一组结果。以你正在阅读的这个博客为例。主页列出了最新的10篇文章。查看下一组最新的帖子需要单击一个按钮。
第二种常见的技术是无限滚动,如果你曾经在Facebook或Twitter上浏览过时间轴,那你可能对无限滚动很熟悉。
苹果新闻app也使用了无限滚动技术来浏览文章列表。
在本文中,我们将更深入地研究第一种类型。分页是我们几乎每天都会遇到的事情,但它并不是不重要的。这是一个很好的组件应用实例,所以这也正是我们要做的。我们将按步骤创建一个负责显示该列表的组件,并在单击要显示的特定页面时触发获取其他文章的操作。换句话说,我们正在用Vue.js创建一个分页组件,就像下面这样:
我们一起来看一看这些步骤。
#步骤1:使用Vue创建ArticlesList组件
我们从创建一个组件开始,该组件将显示文章列表(但目前还没有进行分页)。我们称之为ArticlesList。在该组件模板中,我们将遍历文章的集合,并将单个文章项目传递给每一个ArticleItem组件。
在该组件的脚本部分,我们将设置初始数据:
articles: 这是一个空数组,填充了从mounted钩子上的API获取的数据。 currentPage: 用于操作分页。 pageCount : 这是在基于API响应的mounted钩子上计算的页面总数。 visibleItemsPerPageCount: 这是我们希望在一个页面上看到的文章数量。在这个阶段,我们只获取文章列表的第一页。这将给我们列出两篇文章:
#步骤2: 创建 pageChangeHandle 方法
现在,我们需要创建一个方法来加载下一页、上一页或选定的页面。
在pageChangeHandle方法中,在加载新文章之前,我们根据传递给方法的一个属性来更改currentPage值,并从API获取对应于特定页面的数据。接收到新数据后,我们将用包含新文章页面的新数据替换现有的articles数组。
#步骤3:创建一个组件来触发页面更改
我们已经有了pageChangeHandle方法,但是我们并没有在任何地方触发它。我们需要创建一个负责触发它的组件。
这个组件应该做以下事情:
- 允许用户进入下一页/上一页。 允许用户从当前选定的页面跳转到一个范围内的特定页面。 根据当前页面更改页码的范围。
如果我们把它画出来,它看起来是这样的:
我们继续!
#要求1:允许用户进入下一页或上一页
我们的basePagination将包含两个按钮,负责转到下一页和上一页。
该组件将接受来自父组件的currentPage和pageCount属性,并在下一页或上一页按钮被单击时向父组件返回适当的操作。它还将负责在我们位于第一页或最后一页时禁用按钮,以防止移动出现有集合。
我们将在ArticlesList组件中的ArticleItems下面呈现该组件。
这是比较容易的部分。现在我们需要创建一个页面数量的列表,每个页码允许我们选择一个特定的页面。页面的数量应该是可自定义的,我们还需要确保不显示任何可能导致我们超出集合范围的页面。
#要求2:允许用户进入一个范围内的特定页面
我们从创建一个将用作单个页码的组件开始。我称之为basePaginationTrigger。它将做两件事:显示从basePagination组件传递的页码,并在用户单击特定的页码时发出事件。
然后,这个组件将在下一页和上一页按钮之间的basePagination组件中呈现。
在脚本部分,我们需要添加另一个方法(onLoadPage),该方法将在loadPage事件从触发器组件中发出时触发。此方法将接收已单击的页码,并将事件发送到ArticlesList组件。
然后,在ArticlesList中,我们将监听该事件并触发pageChangeHandle方法,该方法将获取新页面的数据。
#要求3:根据当前页面更改页码范围
现在我们有一个单一的触发器,它显示当前页面并允许我们再次获取相同的页面。这很没用,你不觉得吗? 我们来使用一下新创建的触发器组件。我们需要一个页面列表,该列表允许我们从一个页面跳转到另一个页面,而不需要遍历中间的页面。
我们还需要确保以一种良好的方式显示页面。我们总是希望在分页列表中显示第一个页面(在最左边)和最后一个页面(在最右边),然后在它们之间显示剩余的页面。
我们有三种可能的情况:
- 所选页码小于列表宽度的一半(如1 – 2 – 3 – 4 – 18) 所选页码大于从列表末尾开始计算的列表宽度的一半(例如1 – 15 – 16 – 17 – 18) 所有其他情况(例如1 – 4 – 5 – 6 – 18)
为了处理这些情况,我们将创建一个计算属性,该属性将返回一个应该在下一页和上一页按钮之间显示的数字数组。为了使这个组件更加可重用,我们将接受一个visiblePagesCount属性,该属性将指定在分页组件中多少页面应该可见。
在逐个研究这些情况之前,我们先创建几个变量:
visiblePagesThreshold:- 告诉我们有多少页面来自中心(选定的页面应该被显示) paginationTriggersArray: 将用来填充页码的数组 visiblePagesCount: 创建一个具有所需长度的数组现在我们来看一看每个场景。
场景1: 所选页码小于列表宽度的一半
我们让第一个元素总是等于1。然后我们遍历列表,为每个元素添加一个索引。最后,我们添加最后一个值并将其设置为等于最后一页的页码——如果需要,我们希望能够直接跳到最后一页。
场景2: 所选页码大于从列表末尾开始计算的列表宽度的一半
与前面的场景类似,我们从最后一个页面开始,遍历列表,这次我们从每个元素中减去索引。然后我们反转数组以得到正确的顺序,并将1推入数组的第一个位置。
场景3: 其他所有情况
我们知道列表的中心应该是什么数字:当前页面。我们也知道这个列表应该有多长。这允许我们得到数组中的第一个数字。然后,我们通过向每个元素添加索引来填充列表。最后,我们将1推入数组的第一个位置,并将最后一个数字替换为我们最后一个页码。
这就涵盖了我们所有的场景!我们现在只剩下最后一步了。
#步骤5:在basePagination组件中呈现数字列表
既然我们确切地知道了我们想要在分页中显示的数字,那我们需要为分页中的每一个数字呈现一个触发器组件。
我们使用一个v-for指令来实现。我们还添加了一个条件类,它将处理当前页面的选择。
这样我们就完成了!我们刚刚使用Vue构建了一个很好的可重用分页组件。
#什么时候应该避免这种模式
尽管这个组件非常贴心,但它并不是针对所有涉及分页的用例的灵丹妙药。
例如,对于连续流传输且结构相对扁平的内容,避免这种模式可能是一个好主意,比如每个条目都位于相同的层次结构级别,并且用户对其感兴趣的机会也类似。换句话说,就是不太像一篇有多个页面的文章的东西,而更像主导航的东西。
另一个例子是浏览新闻,而不是寻找特定的新闻文章。我们不需要确切地知道新闻在哪里,也不需要知道我们滚动多少才能看到特定的文章。
#就到这里!
希望这个模式在你的项目中能有用武之地,无论是对于一个简单的博客、一个复杂的电子商务网站,还是介于两者之间的站点。分页可能是一件痛苦的事情,但是拥有一个不仅可以重用而且可以考虑用于大量场景的模块化的模式可以使分页更容易处理。