Skip to main content

使用标准列表控制器

学习目标

完成本单元后,您将能够:

  • 解释 Visualforce 标准列表控制器的含义,以及与标准(记录)控制器的区别。
  • 列出标准列表控制器与标准控制器不同的三个操作。
  • 在 Visualforce 页面上使用标准列表控制器显示记录列表。
  • 定义分页,并将其添加到 Visualforce 页面。
备注

备注

用中文(简体)学习?在中文(简体)Trailhead Playground 中开始挑战,用括号中提供的译文完成挑战。仅复制并粘贴英文值,因为挑战验证基于英文数据。如果在中文(简体)组织中没有成功通过挑战,我们建议您 (1) 将区域设置切换为美国,(2) 按此处说明将语言切换为英文,(3) 再次单击“检查挑战”按钮。

查看 Trailhead 本地化语言徽章详细了解如何利用 Trailhead 译文。

标准列表控制器简介

标准列表控制器允许您创建可以显示或操作一组记录的 Visualforce 页面。

显示记录列表是几乎所有 Web 应用程序的基本行为。Visualforce 只需使用标记,无需后端代码,就可以非常轻松地显示相同类型的记录列表。以往,标准控制器是秘诀,在这种情况下秘诀是标准列表控制器。

标准列表控制器提供了诸多强大的自动行为,例如查询特定对象的记录并使记录在集合变量中可用,以及对结果进行筛选和分页。将标准列表控制器添加到页面与添加标准(记录)控制器非常相似,目的是一次处理多条记录,而不是只处理一条记录。

显示记录列表

使用标准列表控制器和迭代组件,例如使用 <apex:pageBlockTable> 显示记录列表。

标准(记录)控制器可以轻松地将单个记录加载到可以在 Visualforce 页面上使用的变量中。标准列表控制器与之类似,不同的是,它不是将单个记录加载到变量中,而是将记录的列表或集合加载到变量中。

因为您处理的是一个集合,而不是单个记录,所以需要使用迭代组件来显示。迭代组件处理类似项的集合,而不是单个值。迭代组件循环遍历集合,并且对于每个记录,根据作为组件标记的一部分提供的模板生成输出。这听起来很复杂,但是当您阅读标记时,也很快就能理解。

使用标准列表控制器的标记几乎与使用标准的、一次一条记录的控制器相同。为清楚起见,以下示例中以粗体突出显示主要差异。

  1. 要创建新的 Visualforce 页面,请打开 Developer Console,然后单击 File(文件) | New(新建) | Visualforce Page(Visualforce 页面)。输入 ContactList 作为页面名称。
  2. 在编辑器中,将标记替换为以下内容。
    <apex:page standardController="Contact" recordSetVar="contacts">
        <apex:pageBlock title="Contacts List">
            <!-- Contacts List -->
            <apex:pageBlockTable value="{! contacts }" var="ct">
                <apex:column value="{! ct.FirstName }"/>
                <apex:column value="{! ct.LastName }"/>
                <apex:column value="{! ct.Email }"/>
                <apex:column value="{! ct.Account.Name }"/>
            </apex:pageBlockTable>
        </apex:pageBlock>
    </apex:page>
  3. 单击 Preview(预览)可打开页面预览,您可以在进行更改时查看该预览。此时会打开一个新窗口,显示标准 Salesforce 页面标题、侧栏元素、以及联系人列表。标准列表控制器的联系人列表

使用标准列表控制器与使用标准控制器非常相似。首先在 <apex:page> 组件上设置 standardController 属性,然后在同一个组件上设置 recordSetVar 属性。就像使用标准控制器一样,standardController 属性设置要使用的对象。recordSetVar 设置需要使用记录集合创建的变量的名称,此处指 {!contacts }。按照惯例,变量通常被命名为对象名称的复数形式。

<apex:pageBlockTable> 是一个迭代组件,用于生成数据表,并带有平台样式。以下是表格标记中会发生的事情。

  • <apex:pageBlockTable> 的 value 属性设置为标准列表控制器加载的变量 {!contacts }。这是 <apex:pageBlockTable> 将要使用的记录列表。
  • 对于列表中的每条记录,一次一条记录,<apex:pageBlockTable> 将该记录分配给 <apex:pageBlockTable> 的 var 属性中命名的变量。本示例中,变量名称为 ct
  • 对于每条记录,<apex:pageBlockTable> 使用 <apex:pageBlockTable> 主体中的 <apex:column> 列组件集合定义的行在表中构建一个新行。<Apex:column> 组件继而使用表示当前记录的 ct 变量来提取该记录的字段值。
  • 在循环的外部,<apex:pageBlockTable> 使用 <apex:column> 组件中的字段,通过查找每个字段标签的方式来创建列标题。

它涉及大量内容,对于首次接触迭代组件的用户而言,这很难理解。现在您最好尝试创建一个自己的组件。选择要在表中显示的字段。查找 <apex:pageBlockTable><apex:column> 的不同属性,然后进行试验,直到您感觉毫不费力。您还可以尝试使用其他一些迭代组件,例如 <apex:dataList>、又或者是 <apex:repeat>

将筛选列表视图添加到列表中

使用 {! listViewOptions } 获取一个对象可用的列表视图筛选器列表。使用 {! filterId } 设置用于标准列表控制器结果的列表视图筛选器。

标准列表控制器提供了诸多可用于更改列表显示的特性。其中最强大的特性是列表视图筛选器。您可以声明使用单击而不是代码的方式创建列表视图筛选器,标准列表控制器允许您在页面上使用已定义的任意列表视图筛选器。

  1. 将整个 <apex:pageBlock> 封装在 <apex:form> 标签中。要更改标准列表控制器的列表视图筛选器,需要将新值提交回服务器。提交的标准方法是使用通过 <apex:form> 组件创建的表单。
  2. <apex:pageBlock> 标签下,添加以下属性。
id="contacts_list"

这给 <apex:pageBlock> 提供了一个“名称”,我们可以用它来实现很酷的 Ajax 效果,稍后将对此进行解释。

  1. 在起始 <apex:pageBlock> 标签后面、<apex:pageBlockTable> 的上方,添加以下标记。
    Filter:
    <apex:selectList value="{! filterId }" size="1">
        <apex:selectOptions value="{! listViewOptions }"/>
        <apex:actionSupport event="onchange" reRender="contacts_list"/>
    </apex:selectList>
    页面的完整代码如下所示。
    <apex:page standardController="Contact" recordSetVar="contacts">
        <apex:form>
            <apex:pageBlock title="Contacts List" id="contacts_list">
                Filter:
                <apex:selectList value="{! filterId }" size="1">
                    <apex:selectOptions value="{! listViewOptions }"/>
                    <apex:actionSupport event="onchange" reRender="contacts_list"/>
                </apex:selectList>
                <!-- Contacts List -->
                <apex:pageBlockTable value="{! contacts }" var="ct">
                    <apex:column value="{! ct.FirstName }"/>
                    <apex:column value="{! ct.LastName }"/>
                    <apex:column value="{! ct.Email }"/>
                    <apex:column value="{! ct.Account.Name }"/>
                </apex:pageBlockTable>
            </apex:pageBlock>
        </apex:form>
    </apex:page>
    列表上方出现一个新的筛选器控件。带有列表视图筛选器的联系人列表
  2. 从菜单中选择不同的筛选器。联系人列表会发生什么?

从刚创建的筛选器菜单中重新选择时,您应该注意到两件事。首先,当您选择新筛选器时,记录列表会发生变化。(您可能需要尝试几个不同的选项,在标准 DE 组织中使用示例数据时,某些列表视图将显示相同的记录。)

其次,更微妙的是,列表会在不重新加载整个页面的情况下更新。这种 “Ajax” 效果是由 <apex:actionSupport> 组件上的 reRender="contacts_list” 属性提供的。组件和 reRender 的组合效果是仅更新在 reRender 属性中命名的页面部分。由于您将 id="contacts_list” 添加到 <apex:pageBlock>,当操作完成时,在无需重新加载整个页面的情况下,即可实现只更新 <apex:pageBlock> 的效果。

此页面新功能的完整生命周期是这样的。

  • 加载页面时,<apex:selectList>{!listViewOptions } 表达式获取列表,创建可用筛选器菜单。listViewOptions 是标准列表控制器提供的属性。
  • 当您从菜单中选择一个新选项时,<apex:actionSupport> 组件会触发 onchange 事件。
  • onchange 触发时,页面通过将新项目提交给 <apex:selectList> 中设置的 filterId 属性的方式,提交已选择的新列表视图。
  • 当属性更新时,页面从服务器获得新的响应,在 contacts 变量中会有一个新的匹配记录集合。
  • 由于 <apex:actionSupport> 指定只重新渲染页面的一部分,页面是使用 Ajax(异步 JavaScript)更新的,而不是通过重新加载整个页面的方式。

最终结果是,只需添加几行标记,即可实现错综复杂的行为。

向列表添加分页

使用标准列表控制器的分页特性,允许用户单次查看一页长的记录列表。

到目前为止,您开发的功能非常好,并且适用于在 Developer Edition 组织中作为样例数据提供简短记录列表。但是,当您拥有一个真正的组织,组织内有着数百或数千甚至数百万条记录时会发生什么?在单页上查看所有记录,效果并不好!

事实上,标准列表控制器默认情况下只显示符合筛选条件的前 20条记录(如果有的话)。如何让用户访问超出前 20 条的记录,或者每页记录超过 20 条?

分页可以解决这个问题。这是一个标准的 Web 应用程序用户界面元素,通常使用下一页上一页链接,实现在单页的一长串记录中向前或向后移动。您可以使用标准列表控制器将其添加到您的页面中,还可以使用进度指示器和菜单来更改每页记录的数量。

  1. </apex:pageBlockTable> 联系人列表下方,添加以下标记。
<!-- Pagination -->
<table style="width: 100%">
    <tr>
        <td>
            <!-- Page X of Y -->
        </td>
        <td align="center">
            <!-- Previous page -->
            <!-- Next page -->
        </td>
        <td align="right">
            <!-- Records per page -->
        </td>
    </tr>
</table>

这将创建一个 HTML 表,其中将包含您要添加的三个分页控件。

备注

在真实的页面中,您可能会使用更多具有单独样式的语义标记,但目前而言,纯 HTML 更为简洁并且不会妨碍您。

  1. <!-- Page X of Y --> 注释行替换为以下标记。
Page: <apex:outputText value=" {!PageNumber} of {! CEILING(ResultSize / PageSize) }"/>

这会向列表中添加一个进度指示器,指示用户正在查看哪个页面以及剩下多少页面。如果您在 DE 组织中尝试此操作,它可能会显示“Page 1 of 1”(第 1 页,共 1 页)。

  1. <!-- Previous page --><!-- Next page --> 注释行替换为以下标记。
    <!-- Previous page -->
    <!-- active -->
    <apex:commandLink action="{! Previous }" value="« Previous"
         rendered="{! HasPrevious }"/>
    <!-- inactive (no earlier pages) -->
    <apex:outputText style="color: #ccc;" value="« Previous"
         rendered="{! NOT(HasPrevious) }"/>
    <!-- Next page -->
    <!-- active -->
    <apex:commandLink action="{! Next }" value="Next »"
         rendered="{! HasNext }"/>
    <!-- inactive (no more pages) -->
    <apex:outputText style="color: #ccc;" value="Next »"
         rendered="{! NOT(HasNext) }"/>
    该标记在页面上提供上一页下一页链接。标记包含两种可能性:当给定方向有更多记录要查看时,链接处于活动状态;当给定方向没有更多页面时,链接处于禁用状态。
  2. <!-- Records per page --> 注释行替换为以下标记。
    Records per page:
    <apex:selectList value="{! PageSize }" size="1">
        <apex:selectOption itemValue="5" itemLabel="5"/>
        <apex:selectOption itemValue="20" itemLabel="20"/>
        <apex:actionSupport event="onchange" reRender="contacts_list"/>
    </apex:selectList>
    此标记提供用于更改每页记录数的菜单。在这里,我们只添加了一个选项以在页面上显示少量记录。从列表中选择“5”,看看列表和其他控件会发生什么。

结果是一个列表页面,其中包含标准列表控制器提供的诸多功能。

带有分页控件的联系人列表

在进度指示器中,有三个属性用于指示页数,分别是 PageNumberResultSizePageSize。最后两个用于公式表达式,将数字四舍五入到最接近的整数。可防止指示器提示无效信息,例如“Page 2 of 1.6”(第 2 页,共 1.6 页)。

在分页控件中,<apex:commmandLink> 组件引用了标准列表控制器提供的两种操作方法,PreviousNext。结果是执行 PreviousNext 操作的链接。

不过这种渲染属性是什么?它的表达式为 {!HasPrevious }。这就是 Visualforce 有条件地显示组件的方式,即取决于布尔表达式的结果。此处的页面标记引用了标准列表控制器 HasPreviousHasNext 提供的布尔属性,让您清楚在给定方向上是否有更多记录。通过使用渲染属性中的表达式,您可以在页面上显示或隐藏该组件的结果。当您第一次加载页面时,上一页链接置灰,但如果您通过单击下一页链接向前移动时,上一个链接则变为活动状态。

每页选择菜单记录时使用您之前用到的 <apex:selectList>,但我们没有通过调用控制器方法来获取菜单值,而是简单地使用 <apex:selectOption> 元素获取所需的值。每次选定的值发生变化时,<apex:actionSupport> 标记都会再次触发菜单,并再次使用 reRender="contacts_list" 来实现只更新 <apex:pageBlock> 的效果。这里不同的是,使用了 <apex:selectList> 设置标准列表控制器的 PageSize 属性。

了解详细信息...

标准列表控制器提供了诸多 Web 应用程序中常见的功能,远不止本章节介绍的功能。

例如,除了每次向前或向后移动一个页面的 PreviousNext 操作以外,还有指向记录列表开头或结尾的 FirstLast 操作。

标记背后的场景是基于 StandardSetController Apex 类的标准列表控制器。您可以通过 Lightning 平台 Apex 代码开发人员指南了解标准列表控制器的更多信息及其提供的功能。

这里创建的示例有一个小问题,示例名称会进行排序。通常希望列表有默认的排序顺序,还希望有影响排序的列标题,以便动态更改排序顺序。而事实是仅使用 Visualforce 是无法影响排序顺序的。尽管支持排序和可单击列标题所需的额外 Visualforce 标记和 Apex 代码数量不多,但确实需要自定义代码。初学阶段请多参阅其他资源。

资源

在 Salesforce 帮助中分享 Trailhead 反馈

我们很想听听您使用 Trailhead 的经验——您现在可以随时从 Salesforce 帮助网站访问新的反馈表单。

了解更多 继续分享反馈