Lightning-设计(6)布置记录主页

学习目标

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

  • 使用网格系统布局一个记录主页。
  • 使用卡组件的两种变体来呈现记录相关列表。

大压轴

感谢您坚持使用模块!在这个最后的单元中,我们将打造另一个全新的页面,神奇地再次符合Lightning UI,而不需要我们写一行CSS。在之前的模块中,我们将使用许多我们已经了解的组件,包括网格系统,页面标题和图标。我们还将介绍一些关键的新组件Card和Tile。

有问题的页面将成为一个记录主页。为什么这个网页?我们认为这是许多应用程序页面的原型,在许多方面它是传统的Salesforce页面。这个例子将是你的应用程序的基础模板。这也是复杂的,但不是太复杂,所以它会很好的练习,你会在这个过程中赚取Trailhead徽章!让我们开始?

记录页面布局

这是我们要去的页面的一个线框。页面顶部有两个相关的列表,左边是一个大的列表,右边是一个紧凑的卡片。在下面,我们有通常的页脚。好消息是,我们将能够重用我们之前编写的一堆标记。

Record home wireframe

让我们从一个名为Trailhead_SLDS_RecordHome的全新Visualforce页面开始使用外部页面框架。

<apex:page showHeader="false" standardStylesheets="false" sidebar="false" applyHtmlTag="false" applyBodyTag="false" docType="html-5.0">

<html xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" lang="en">
<head>
  <meta charset="utf-8" />
  <meta http-equiv="x-ua-compatible" content="ie=edge" />
  <title>Salesforce Lightning Design System Trailhead Module</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />

  <!-- 导入设计系统样式表 -->
  <apex:slds />
</head>
<body>

  <!-- 需要的SLDS包装 -->
  <div class="slds-scope">

    <!-- MASTHEAD -->
    <p class="slds-text-heading--label slds-m-bottom--small">Salesforce Lightning Design System Trailhead Module</p>
    <!-- / MASTHEAD -->

    <!-- PAGE HEADER -->
    <!-- / PAGE HEADER -->

    <!-- PRIMARY CONTENT WRAPPER -->
    <div class="myapp">
    </div>
    <!-- / PRIMARY CONTENT WRAPPER -->

    <!-- FOOTER -->
    <footer role="contentinfo" class="slds-p-around--large">
      <!-- 布局网格 -->
      <div class="slds-grid slds-grid--align-spread">
        <p class="slds-col">Salesforce Lightning Design System Example</p>
        <p class="slds-col">&copy; Your Name Here</p>
      </div>
      <!-- / 布局网格 -->
    </footer>
    <!-- / FOOTER --> 

  </div>
  <!-- / 需要的SLDS包装 -->

  <!-- JAVASCRIPT -->
  <!-- / JAVASCRIPT -->

</body>
</html>
</apex:page>
添加页眉

接下来,我们将添加一个Page Header组件,这个比我们在列表视图中使用的组件要多一点。我们将有两排。第一个和列表视图非常相似。第二行将显示记录中的一些关键字段。

第一行的代码现在应该看起来很熟悉。把它放在<! – PAGE HEADER – >之间:

<!-- PAGE HEADER -->
<div class="slds-page-header">

  <!-- PAGE HEADER TOP ROW -->
  <div class="slds-grid">

    <!-- PAGE HEADER / ROW 1 / COLUMN 1 -->
    <div class="slds-col slds-has-flexi-truncate">

      <!-- HEADING AREA -->
      <!-- 媒体对象 = FIGURE + BODY -->
      <div class="slds-media slds-no-space slds-grow">
        <div class="slds-media__figure">
          <svg aria-hidden="true" class="slds-icon slds-icon-standard-user">
            <use xlink:href="{!URLFOR($Asset.SLDS, 'assets/icons/standard-sprite/svg/symbols.svg#user')}"></use>
          </svg>
        </div>

        <div class="slds-media__body">
          <p class="slds-text-title--caps slds-line-height--reset">Account</p>
          <h1 class="slds-page-header__title slds-m-right--small slds-align-middle slds-truncate" title="SLDS Inc.">SLDS Inc.</h1>
        </div>
      </div>
      <!-- / 媒体对象 -->
      <!-- HEADING AREA -->

    </div>
    <!-- / PAGE HEADER / ROW 1 / COLUMN 1 -->

    <!-- PAGE HEADER / ROW 1 / COLUMN 2 -->
    <div class="slds-col slds-no-flex slds-grid slds-align-top">
      <div class="slds-button-group" role="group">
        <button class="slds-button slds-button--neutral">
          Contact
        </button>
        <button class="slds-button slds-button--neutral">
          More
        </button>
      </div>
    </div>
    <!-- / PAGE HEADER / ROW 1 / COLUMN 2 -->

  </div>
  <!-- / PAGE HEADER TOP ROW -->

  <!-- 页眉细节行 -->
  <!-- / PAGE HEADER DETAIL ROW -->

</div>
<!-- / PAGE HEADER -->
预览您的页面,您将看到预期的页眉的顶部行。如果任何代码不清楚,请参考之前的单元或相应的组件文档。

Record home with partial header

接下来让我们使用另一个Grid System组件实现第二个详细信息行。它将包含四列。在<! – PAGE HEADER DETAIL ROW – >占位符注释中包含以下代码:

<!-- 页眉细节行 -->
<ul class="slds-grid slds-page-header__detail-row">

  <!-- PAGE HEADER / ROW 2 / COLUMN 1 -->
  <li class="slds-page-header__detail-block">
    <p class="slds-text-title slds-truncate slds-m-bottom--xx-small" title="Field 1">Field 1</p>
    <p class="slds-text-body--regular slds-truncate" title="Description that demonstrates truncation with a long text field">Description that demonstrates truncation with a long text field.</p>
  </li>

  <!-- PAGE HEADER / ROW 2 / COLUMN 2 -->
  <li class="slds-page-header__detail-block">
    <p class="slds-text-title slds-truncate slds-m-bottom--xx-small" title="Field2 (3)">Field 2 (3)
      <button class="slds-button slds-button--icon" aria-haspopup="true" title="More Actions">
        <svg class="slds-button__icon slds-button__icon--small" aria-hidden="true">
          <use xlink:href="/assets/icons/utility-sprite/svg/symbols.svg#down"></use>
        </svg>
        <span class="slds-assistive-text">More Actions</span>
      </button>
    </p>
    <p class="slds-text-body--regular">Multiple Values</p>
  </li>

  <!-- PAGE HEADER / ROW 2 / COLUMN 3 -->
  <li class="slds-page-header__detail-block">
    <p class="slds-text-title slds-truncate slds-m-bottom--xx-small" title="Field 3">Field 3</p><a href="javascript:void(0);">Hyperlink</a></li>

  <!-- PAGE HEADER / ROW 2 / COLUMN 4 -->
  <li class="slds-page-header__detail-block">
    <p class="slds-text-title slds-truncate slds-m-bottom--xx-small" title="Field 4">Field 4</p>
    <p>
      <span title="Description (2-line truncation—must use JS to truncate).">Description (2-line truncat...</span>
    </p>
  </li>
</ul>
<!-- / PAGE HEADER DETAIL ROW -->
预览页面,你会看到完整的标题,第二行填充记录中的关键字段:

Record home with complete header

另外,设计系统让我们的生活变得非常简单。这段代码在不输入CSS字符的情况下展示了符合Lightning UI规范的复杂组件。让我们一步一步浏览详细信息的代码。再次,我们建议在您最喜欢的编辑器中打开代码,除了这个窗口,所以你可以交叉引用。

外部的<ul>实例化我们的网格,并添加类slds-page-header__detail-行来正确对齐。

这四个字段使用一系列带有slds-page-header__detail-block类的<li>进行布局。

在每个细节块中,我们有一个或多个带有三个类的<p>元素:slds-text-title,slds-m-bottom-xx-small在它们下面增加空格,以及slds-truncate截断字段值。

您可以在Page Header组件页面上看到完整的记录主页页眉示例。

添加主要相关列表

现在让我们进入记录家庭细节区域,我们想要两个相关的列表并排。

在<! – PRIMARY CONTENT WRAPPER – >注释中包含以下代码:

<!-- PRIMARY CONTENT WRAPPER -->
<div class="myapp">

  <!-- 相关名片卡-->

  <div class="slds-grid slds-m-top--large">

    <!-- 主卡 -->
    <div class="slds-col slds-col-rule--right slds-p-right--large slds-size--8-of-12">
      left hand column related list
    </div>
    <!-- / 主卡 -->

    <!-- 狭窄的卡片  -->
    <div class="slds-col slds-p-left--large slds-size--4-of-12">
      right hand column related list
    </div>
    <!-- / 狭窄的卡片  -->

  </div>
  <!-- / 相关名片卡 -->

</div>
<!-- / PRIMARY CONTENT WRAPPER -->
我们使用另一个Grid System组件来使用尺寸助手类来手动调整两个列的大小。第一列将包含一个大的相关名单卡。较窄的右列将包含一个小型卡。其中每一个都是卡组件的变体。

这是左手卡的代码。把它放在<! – MAIN CARD – >评论:

<!-- 主卡  -->
<div class="slds-col slds-col-rule--right slds-p-right--large slds-size--8-of-12">

  <article class="slds-card">

    <div class="slds-card__header slds-grid">
      <header class="slds-media slds-media--center slds-has-flexi-truncate">
        <div class="slds-media__figure">
          <svg aria-hidden="true" class="slds-icon slds-icon-standard-contact slds-icon--small">
            <use xlink:href="{!URLFOR($Asset.SLDS, 'assets/icons/standard-sprite/svg/symbols.svg#contact')}"></use>
          </svg>
        </div>
        <div class="slds-media__body slds-truncate">
          <a href="javascript:void(0);" class="slds-text-link--reset">
            <span class="slds-text-heading--small">Contacts</span>
          </a>
        </div>
      </header>
    </div>

    <!-- CARD BODY = TABLE -->
    <div class="slds-card__body">
      <table class="slds-table slds-table--bordered slds-no-row-hover slds-table--cell-buffer">
        <thead>
          <tr class="slds-text-heading--label">
            <th class="slds-size--1-of-4" scope="col">Name</th>
            <th class="slds-size--1-of-4" scope="col">Company</th>
            <th class="slds-size--1-of-4" scope="col">Title</th>
            <th class="slds-size--1-of-4" scope="col">Email</th>
            <th scope="col"></th>
          </tr>
        </thead>
        <tbody>
          <tr class="slds-hint-parent">
            <th class="slds-size--1-of-4" scope="row"><a href="javascript:void(0);">Adam Choi</a></th>
            <td class="slds-size--1-of-4">Company One</td>
            <td class="slds-size--1-of-4">Director of Operations</td>
            <td class="slds-size--1-of-4">adam@company.com</td>
            <td class="slds-cell-shrink">
              <button class="slds-button slds-button--icon-border-filled slds-button--icon-x-small">
                <svg aria-hidden="true" class="slds-button__icon slds-button__icon--hint slds-button__icon--small">
                  <use xlink:href="{!URLFOR($Asset.SLDS, 'assets/icons/utility-sprite/svg/symbols.svg#down')}"></use>
                </svg>
                <span class="slds-assistive-text">Show More</span>
              </button>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
    <!-- / CARD BODY = SECTION + TABLE -->

    <div class="slds-card__footer">
      <a href="javascript:void(0);">View All <span class="slds-assistive-text">contacts</span></a>
    </div>

  </article>
</div>
<!-- / MAIN CARD -->
预览页面以查看第一个相关列表:

Record home with main related list

现在这个演示只是一个联系人的例子,所以不要把这个展示给你的销售人员!在现实生活中,你会加载更多的人来卖东西!

让我们一步一步通过标记。

卡组件包装在<article class =“slds-card”>元素中。

卡头由一个带有slds-card_header和slds-grid类的<div>元素指定。这两列分别包含一个媒体对象和一个操作按钮。在列表视图中,可以使用Button Group组件轻松扩展第二列。一如既往,您可以在Design System网站上找到所有这些类的更多文档和示例。

卡体是类slds-card__body的<div>元素。里面有一个数据表组件。

该卡片在<div class =“slds-card__footer”>内完成了“查看全部”链接。

添加最终的窄卡

我们的记录家的最后一步是添加右侧窄卡。为此,我们使用卡组件的窄型变体。这里是<! – NARROW CARD – >注释中的标记:

<!-- 狭窄的卡片 -->
<div class="slds-col slds-p-left--large slds-size--4-of-12">

  <article class="slds-card slds-card--narrow">

    <div class="slds-card__header slds-grid">
      <header class="slds-media slds-media--center slds-has-flexi-truncate">
        <div class="slds-media__figure">
          <svg class="slds-icon slds-icon-standard-lead slds-icon--small" aria-hidden="true">
            <use xlink:href="{!URLFOR($Asset.SLDS, 'assets/icons/standard-sprite/svg/symbols.svg#lead')}"></use>
          </svg>
        </div>
        <div class="slds-media__body slds-truncate">
          <h2 class="slds-text-heading--small">Team</h2>
        </div>
      </header>
    </div>

    <div class="slds-card__body">
      <div class="slds-card__body--inner">
        <div class="slds-tile">
          <h3 class="slds-truncate" title="Anne Choi"><a href="javascript:void(0);">Anne Choi</a></h3>
          <div class="slds-tile__detail slds-text-body--small">
            <dl class="slds-list--horizontal slds-wrap">
              <dt class="slds-item--label slds-text-color--weak slds-truncate" title="Email:">
                Email:
              </dt>
              <dd class="slds-item--detail slds-truncate" title="achoi@burlingtion.com">
                achoi@burlingtion.com
              </dd>
            </dl>
          </div>
        </div>
      </div>
    </div>

    <div class="slds-card__footer">
      <a href="javascript:void(0);">View All <span class="slds-assistive-text">team members</span></a>
    </div>

  </article>

</div>
<!-- / 狭窄的卡片 -->
像全尺寸的卡一样,狭窄的卡被指定为一个slds-card类,我们添加一个slds-card-narrow修饰符类。和以前一样,我们提供一个卡头和一个卡体。

狭窄的卡体是一系列瓷砖组件。平铺是与记录相关的一组相关信息。这个组件有几个变体,每个变体都有不同的信息分组。密切关注文档中提供的示例中的标记,因为每个拼贴布局的构造都是不同的。这里我们使用最简单的基础变体。

每个瓦片都有slds-tile类。在里面,我们提供了一个名片和一些内容。和以前一样,我们使用与其他卡片相同的<div class =“slds-card__footer”>标记来包装窄卡。

您现在应该能够预览完整的记录主页:

Record home with narrow card

这个相当复杂的录制家庭标记的完整示例将使此Trailhead模块关闭。希望你现在在设计系统有一个坚实的基础,并渴望在你自己的应用程序中使用它。

显然,这些示例页面仅仅是开始。在构建自己的应用程序时,下一步就是挂钩实际数据,链接页面,并构建业务逻辑。我们希望设计系统能够让您从CSS的样式化UI中解脱出来,所以您可以专注于构建这个真正的功能。玩得开心,请给我们反馈你如何得到。

Lightning-设计(5)图片

学习目标

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

  • 使用图像组件将头像添加到您的设计中。
  • 使用设计系统SVG精灵贴图将图标包含在您的设计中。
  • 描述在Visualforce中工作时的标记陷阱。

阿凡达告诉千言万语

在本节中,我们将使用图像和一组全新的漂亮图标(更多内容在下面)使事情变得更加明亮。这可能听起来很简单…整个图像单元,真的吗?但是,这些是关键组件,特别是你会看到我们正在使用一些尖端的技术来为我们的图标标记。另外,你需要照亮你的示例页面,以获得这些Trailhead徽章。

在我们进入代码之前,请注意可访问性。请记住,每个<img />标签都应具有辅助技术用户的alt属性。如果图像载有信息,请将alt设置为简明的描述。如果图片仅仅是装饰性的,或者对于相邻的文字是多余的,请设置一个空的alt属性,如下所示:<img alt =“”src =“decorative-image.jpg”/>

图像方面,设计系统包括化身的特殊样式。你知道,那些你周围在互联网上看到的髋关节圆形图像。

Example avatars

头像是通过将<img />元素用类slds-avatar包装在<span>元素中创建的。可以应用其他大小助手类,例如slds-avatar – large。设计系统下载实际上包括/ assets / images下的几个头像示例。请随意将它们包含在您的应用程序中。这是一个标记的例子:

<span class="slds-avatar slds-avatar--x-small">
  <img src="/assets/images/avatar1.jpg" alt="meaningful text" />
</span>

媒体对象

在Web应用程序中包含图像的常见模式是并排包含图像和文本。该设计系统有一个组件,使这超级简单,媒体对象。

让我们直接回到最后一个单元的代码。我们将使用媒体对象在页面标题中包含一个头像。用下面的代码替换页头中的<! – HEADING AREA – >部分:

<!-- HEADING AREA -->
<div class="slds-media slds-no-space slds-grow">
  <div class="slds-media__figure">
    <span class="slds-avatar slds-avatar--medium">
      <img src="{!URLFOR($Asset.SLDS, 'assets/images/avatar1.jpg')}" alt="" />
    </span>
  </div>
  <div class="slds-media__body">
    <p class="slds-text-title--caps slds-line-height--reset">Accounts</p>
    <h1 class="slds-page-header__title slds-m-right--small slds-align-middle slds-truncate" title="My Accounts">My Accounts</h1>
  </div>
</div>
<!-- / HEADING AREA -->
预览您的网页,并注意它是如何开始获得更多的视觉吸引力。

List view with avatar

媒体对象组件的基类是slds-media。它可以应用于任何容器元素,这里我们使用一个<div>。在容器内部,我们提供一个图形(图像)和一个实体(内容)。

这个数字,也就是我们的头像,被包含在一个带有slds-media__figure类的<span>中。头像图像是用标准的<img />元素指定的。你也可以在这里包含一个图标(见下文)。

正文是类slds-media__body的<div>。这包裹了我们之前使用的标题文本。

图标

在我们开始这项工作时,更新Salesforce图标是我们的首要任务。让我们面对现实,现有的“剪贴画”看起来有点憔悴和90年代。因此,我们非常高兴能够提供这套令人兴奋的Technicolor图标,涵盖各种用例供您在自己的应用程序中使用。

设计系统包括五种不同类型的新图标:

  • 自定义 – 这些图标代表我们UI中的自定义Salesforce对象。它们是我们在创建自定义对象时向Salesforce管理员提供的图标
  • 文档类型 – 常用的文档和文件格式
  • 标准 – 这些图标涵盖了我们UI中的所有标准Salesforce对象
  • 实用程序 – 关闭模式,返回上一页或打开下拉菜单
  • 行动 – 最后,但并非最不重要的,好行动类别。我们在我们的移动用户界面中使用这些图标作为相当具体的用例。你会发现这里有一些重复的标准和自定义设置 – 不要惊慌,你不会发疯。很可能你完全可以忽略这个类别,并且仍然有足够的图标用于你可以梦想的任何用例。

Example icons

这些图标既作为单独的PNG和SVG提供,也包装在SVG sprite地图中。以上每个图标类别在/ assets /图标下都有自己的精灵贴图。雪碧地图是我们推荐的在页面中包含图标的技术。与传统的图标字体相比,SVG sprite映射的优点包括更细粒度的CSS控制和更容易的组件定位,以及更好的基于矢量SVG的可调整性。这最后的好处是响应式设计的福音。基于矢量的图像可以制作任何尺寸的清洁艺术品。

请注意:Edge,Google Chrome,Safari和Firefox的当前版本已经支持SVG精灵贴图。要在Microsoft Internet Explorer 11中使用SVG spritemap图像图标,您需要下载一个名为svg4everybody的小脚本。下载svg4everybody之后,将svg4everybody.min.js脚本添加为静态资源,将其包含在您的页面中,然后在<script>标记中调用它。请参阅svg4everybody网站上的完整说明了解更多详情。使用这种图标技术(如前一段所述)的优点不仅仅是弥补了这一额外的步骤。

  <apex:includeScript value="{!$Resource.REPLACE_WITH_NAME_OF_SVG4EVERYBODY_STATIC_RESOURCE}" />
  <script>
    svg4everybody();
  </script>
</head>
SVG精灵贴图也是为什么我们要添加xmlns和xmlns:xlink属性到你的<html>元素。原因是在Visualforce中配置SVG和xlink命名空间。再次,一小部分的工作,以获得巨大的回报。
<html xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" lang="en">
设计系统的图标标记对于许多读者来说是新的,所以我们来看一个例子。这是一个独立图标的标记。假设用户界面中的位置对用户有一定的意义(即图标不是装饰性的)。这意味着我们需要提供一些辅助文字以及我们的图标:
<span class="slds-icon_container slds-icon-standard-account" title="description of icon when needed">
  <svg aria-hidden="true" class="slds-icon">
    <use xlink:href="{!URLFOR($Asset.SLDS, 'assets/icons/standard-sprite/svg/symbols.svg#account')}"></use>
  </svg>
  <span class="slds-assistive-text">Account Icon</span>
</span>
让我们一步一步通过这个元素,并按类来分类。由于该图标是独立的,并带有含义,因此我们将其放置在slds-icon_container类的外部跨度内。

图标没有背景颜色。为了设置一个,我们将第二个类应用到该跨度。要为特定图标使用默认颜色,请通过连接slds-icon-,sprite映射名称和-icon来构造图标特定实用程序类的名称。将该类应用于<span>元素。在这个例子中,我们使用“标准”精灵图和“客户”图标,所以类是slds-icon-standard-account。

在<span>中,我们有一个带有slds-icon类的<svg>元素。 <svg>元素又包含一个<use>标签,它根据xlink:href属性指定要显示的图标。

为了设置xlink:href路径,请执行以下步骤:

  1. 首先从图标页面中选择您要使用的图标。记下它在哪个类别(动作,自定义,文档类型,标准或实用程序)。
  2. 通过连接类别精灵(例如“standard-sprite”),/svg/symbols.svg#和其中的特定图标(例如“account”)来完成xlink:href属性。因此,在上面的例子中,路径assets / icons / standard-sprite / svg / symbols.svg#是客户。

如果图标没有出现,请检查以下内容:

  • 检查是否已将xmlns和xmlns:xlink属性应用于您的<html>元素
  • 如果您使用的是MSIE,请确保使用最新版本,并按照上文所述在页面中包含svg4everybody脚本。
  • 确保在svg路径中正确指定了sprite类型和图标
  • 仔细检查你的静态资源是否有正确的URLFOR路径
  • 最后,请查看浏览器开发者工具中的页面,了解真正疯狂的深奥问题。祝你好运。

在<svg>标签之后,辅助文本被包含在slds-assistive-text类的跨度内。

有关使用图标的更多信息(如更改图标颜色或大小),请参阅Design System网站上的图标组件文档。

将图标添加到列表视图数据表

现在,让一些帐户图标照亮数据表。将updateOutputDiv函数替换为以下内容以添加一个带有图标的附加列:

var updateOutputDiv = function() {

  account.retrieve(
    { orderby: [{ LastModifiedDate: 'DESC' }], limit: 10 },
    function(error, records) {
      if (error) {
        alert(error.message);
      } else {
        // 创建数据表
        var dataTable = document.createElement('table');
        dataTable.className = 'slds-table slds-table--bordered slds-table--cell-buffer slds-no-row-hover';

        // 添加标题行
        var tableHeader = dataTable.createTHead();
        var tableHeaderRow = tableHeader.insertRow();

        var tableHeaderRowCellIcon = tableHeaderRow.insertCell(0);
        tableHeaderRowCellIcon.setAttribute('class', 'slds-cell-shrink');

        var tableHeaderRowCell1 = tableHeaderRow.insertCell(1);
        tableHeaderRowCell1.appendChild(document.createTextNode('Account name'));
        tableHeaderRowCell1.setAttribute('scope', 'col');
        tableHeaderRowCell1.setAttribute('class', 'slds-text-heading--label');

        var tableHeaderRowCell2 = tableHeaderRow.insertCell(2);
        tableHeaderRowCell2.appendChild(document.createTextNode('Account ID'));
        tableHeaderRowCell2.setAttribute('scope', 'col');
        tableHeaderRowCell2.setAttribute('class', 'slds-text-heading--label');


        // 建立表体
        var tableBody = dataTable.appendChild(document.createElement('tbody'))
        var dataRow, dataRowCell1, dataRowCell2, recordName, recordId;
        records.forEach(function(record) {
          dataRow = tableBody.insertRow();

          var sldsSpriteReference = document.createElementNS('http://www.w3.org/2000/svg', 'use');
          sldsSpriteReference.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '{!URLFOR($Asset.SLDS, 'assets/icons/standard-sprite/svg/symbols.svg#account')}');
          var accountIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
          accountIcon.setAttributeNS('http://www.w3.org/2000/svg', 'aria-hidden', true);
          accountIcon.classList.add('slds-icon');
          accountIcon.appendChild(sldsSpriteReference);
          accountIconWrapper = document.createElement('span');
          accountIconWrapper.classList.add('slds-icon_container', 'slds-icon-standard-account');
          accountIconWrapper.appendChild(accountIcon);
          dataRowCellIcon = dataRow.insertCell(0);
          dataRowCellIcon.appendChild(accountIconWrapper);

          dataRowCell1 = dataRow.insertCell(1);
          recordName = document.createTextNode(record.get('Name'));
          dataRowCell1.appendChild(recordName);

          dataRowCell2 = dataRow.insertCell(2);
          recordId = document.createTextNode(record.get('Id'));
          dataRowCell2.appendChild(recordId);
        });

        if (outputDiv.firstChild) {
          // replace table if it already exists
          // see later in tutorial
          outputDiv.replaceChild(dataTable, outputDiv.firstChild);
        } else {
          outputDiv.appendChild(dataTable);
        }
      }
    }
  );
}
预览你的页面,你应该看到一些近似真实的用户界面。现在检查一下这个单元,注意这个CSS有多少行。

Data table with icons

在下一个单元中,我们在最着名的Salesforce页面之一上工作:臭名昭着的记录主页。这将把我们在单元中学到的技能和组件结合到一起,并引入一些额外的设计系统组件。

Lightning-设计(4)读取数据

学习目标

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

  • 描述SLDS数据表和表单组件如何工作。
  • 使用JavaScript远程对象构建包含动态数据的列表视图页面。

将数据添加到混合

让我们面对它,Web应用程序是不是很令人兴奋,除非它们包含一些数据。这个单元是关于使我们的列表视图是真实的,并使用开发者组织的一些示例数据。

我们将使用JavaScript Remote Objects访问Salesforce数据,但您也可以使用JavaScript Remoting。请注意,设计系统尚不支持Apex标签,但Visualforce可视化设计考虑事项上的Trailhead单元解释了遗留代码样式的选项,使其看起来像新的Lightning UI。

本单元中的JavaScript不在设计系统的范围之内,但它有助于将我们的一些关键组件生命化并展示它们的使用方式。再加上它会让事情变得更有趣。

数据表组件

数据表组件是用于使用Lightning UI样式显示表格数据的HTML表格的增强版本。数据表是通过将slds-table类应用于<table>标签而创建的。使用slds-table-bordered类来应用边界。

这是一个包含两列和一个标题行的示例表。您可以看到,其应用了设计系统类的熟悉的HTML标记。再次没有任何CSS可以看到。不用担心输入,下一节我们将使用Salesforce数据动态填充真实的数据表。

<table class="slds-table slds-table--bordered slds-table--cell-buffer slds-no-row-hover">
  <thead>
    <tr class="slds-text-heading--label">
      <th scope="col">Account ID</th>
      <th scope="col">Account name</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">123</th>
      <td>Account 1</td>
    </tr>
    <tr>
      <th scope="row">456</th>
      <td>Account 2</td>
    </tr>
  </tbody>
</table>

用动态数据填充数据表

正如我们上面提到的那样,在这个版本中,设计系统不支持内置的Visualforce组件 – <apex:*>,<chatter:*>以及其他您熟悉和喜欢的组件 – 用于布置页面和访问数据。这一点很重要。不要指望将设计系统应用到您的传统Visualforce页面,并让他们立即转化为互联网上最美丽的用户界面。

目前,我们建议使用远程对象,JavaScript Remoting或REST API从基于Design System标记的Visualforce页面访问Salesforce数据。本教程中的示例将使用远程对象。我们在这里专注于设计系统,所以虽然我们将提供完整的代码,但我们不打算深入讨论远程对象部分。如果您想了解有关这些数据访问技术的更多信息,请参阅以下资源。

我们走吧。摇动你的手来预热 – 是时候编码了。使用名称Trailhead_SLDS_Listview_Data克隆您的列表视图页面作为新的Visualforce页面。然后通过在</ head>和<body>标记之间插入以下代码,将Salesforce组织的客户记录连接为远程对象:

</head>    

<apex:remoteObjects>
  <apex:remoteObjectModel name="Account" fields="Id,Name,LastModifiedDate"/>
</apex:remoteObjects>

<body>
接下来,我们用slds-p-vertical-medium类中的垂直填充替换无聊的<ul>占位符与客户列表<div>。我们的JavaScript很快将用我们完全呈现的数据表来替换这个<div>的空白内容。
<!-- PRIMARY CONTENT WRAPPER -->
<div class="myapp">

  <!-- 客户列表 -->
  <div id="account-list" class="slds-p-vertical--medium"></div>
  <!-- / 客户列表 -->

</div>
<!-- / PRIMARY CONTENT WRAPPER -->
最后在</ body>结束标记之前的文件末尾添加以下JavaScript代码。请注意,在您自己的代码中,您可能希望将此JavaScript放在单独的静态资源中。
<!-- JAVASCRIPT -->
<script>
  (function() {
    var account = new SObjectModel.Account();
    var outputDiv = document.getElementById('account-list');

    var updateOutputDiv = function() {

      account.retrieve(
        { orderby: [{ LastModifiedDate: 'DESC' }], limit: 10 },
        function(error, records) {
          if (error) {
            alert(error.message);
          } else {
            // create data table
            var dataTable = document.createElement('table');
            dataTable.className = 'slds-table slds-table--bordered slds-table--cell-buffer slds-no-row-hover';

            // add header row
            var tableHeader = dataTable.createTHead();
            var tableHeaderRow = tableHeader.insertRow();

            var tableHeaderRowCell1 = tableHeaderRow.insertCell(0);
            tableHeaderRowCell1.appendChild(document.createTextNode('Account name'));
            tableHeaderRowCell1.setAttribute('scope', 'col');
            tableHeaderRowCell1.setAttribute('class', 'slds-text-heading--label');

            var tableHeaderRowCell2 = tableHeaderRow.insertCell(1);
            tableHeaderRowCell2.appendChild(document.createTextNode('Account ID'));
            tableHeaderRowCell2.setAttribute('scope', 'col');
            tableHeaderRowCell2.setAttribute('class', 'slds-text-heading--label');

            //建立表体
            var tableBody = dataTable.appendChild(document.createElement('tbody'))
            var dataRow, dataRowCell1, dataRowCell2, recordName, recordId;
            records.forEach(function(record) {
              dataRow = tableBody.insertRow();

              dataRowCell1 = dataRow.insertCell(0);
              recordName = document.createTextNode(record.get('Name'));
              dataRowCell1.appendChild(recordName);

              dataRowCell2 = dataRow.insertCell(1);
              recordId = document.createTextNode(record.get('Id'));
              dataRowCell2.appendChild(recordId);
            });

            if (outputDiv.firstChild) {
              // replace table if it already exists
              // see later in tutorial
              outputDiv.replaceChild(dataTable, outputDiv.firstChild);
            } else {
              outputDiv.appendChild(dataTable);
            }
          }
        }
      );
    }
    updateOutputDiv();
  })();
</script>
<!-- / JAVASCRIPT -->

此代码通过远程对象访问客户记录,updateOutputDiv()函数使用它们在客户列表<div>中呈现表。

请注意表是如何用slds-scrollable -x工具类包装在一个div中的。如果数据太宽而无法在屏幕上显示,则会为该表提供一个水平滚动条。

预览你的页面,应该看起来像下面这样。不过希望你的客户名更具创意。

Populated data table

填充的数据表

我们在这里仍然可以做得更好。让我们互动吧。在这一步中,您将在Visualforce页面的顶部添加一个基本表单,允许用户创建一个新客户。将以下代码插入到您的主要内容包装中,在客户列表上方

<!-- PRIMARY CONTENT WRAPPER -->
<div class="myapp">

  <!-- 创建新客户  -->
  <div aria-labelledby="newaccountform">

    <!-- 创建新客户表单 -->
    <form class="slds-form--stacked" id="add-account-form">
      <!-- BOXED AREA -->
      <fieldset class="slds-box slds-theme--default slds-container--small">

        <legend id="newaccountform" class="slds-text-heading--medium slds-p-vertical--medium">Add a new account</legend>

        <div class="slds-form-element">
          <label class="slds-form-element__label" for="account-name">Name</label>
          <div class="slds-form-element__control">
            <input id="account-name" class="slds-input" type="text" placeholder="New account"/>
          </div>
        </div>
        <button class="slds-button slds-button--brand slds-m-top--medium" type="submit">Create Account</button>
      </fieldset>
      <!-- / BOXED AREA -->
    </form>
    <!-- 创建新客户表单 -->

  </div>
  <!-- / 创建新客户 -->

</div>
<!-- / PRIMARY CONTENT WRAPPER -->
...
这里还有很多新的标记。让我们一步一步的审查。

表单标记被封装到一个<div>包装器中以添加页面结构。

现在我们发现另一个设计系统组件:表单。设计系统为多种表单布局提供样式,包括水平,堆叠和内联。在这个例子中,我们使用slds-form-stacked类将一个垂直堆叠布局应用于<form>。

在表单里面是第二个包装元素,一个<fieldset>包含三个类:slds-box,slds-theme-default和slds-container-small。这三个班级创造了一个白色的,盒装的,小的区域,以保持视觉的美观和整洁。 <legend>标签中的标题在框的顶部添加了一个标题。 <legend>元素的id属性对应于包装器<div>元素的aria-labelledby属性,以实现可访问性。

每个标签和输入对都放在一个包含slds-form-element的包装盒中,以提供最佳的间距。在包装器中,<label>元素有一个slds-form-element__label类。 <input>字段放置在另一个包装器<div>中,并带有slds-form-element__control类,以提供最佳的间距。 <input>字段本身具有slds-input类。

在你的表单中添加所有这些标记和类,几乎可以自动地将所有的Lightning样式应用于自己。您添加类,我们提供所有的CSS。

我们不要忘记,用户必须能够提交表单。因此,我们包含一个<按钮>类slds-button,slds-button-brand和slds-m-top-medium。这些现在应该是不言自明的。如果没有,请参阅链接的文档。

最后,我们需要通过一种方式来连接表单,以实际保存表单的数据。我们将使用一个createAccount()JavaScript函数来完成此工作,该函数再次使用远程对象来完成这项工作。在updateOutputDiv()函数下面添加以下内容:

var accountForm = document.getElementById('add-account-form');
var accountNameField = document.getElementById('account-name');

var createAccount = function() {
  var account = new SObjectModel.Account();
  account.create({ Name: accountNameField.value }, function(error, records) {
    if (error) {
      alert(error.message);
    } else {
      updateOutputDiv();
      accountNameField.value = '';
    }
  });
}
accountForm.addEventListener('submit', function(e) {
  e.preventDefault();
  createAccount();
});
提交表单调用了createAccount()函数,它调用我们的远程对象来创建一个新记录。

预览您的页面,然后尝试添加一些客户。 每次您使用有效的客户名称提交表格时,表格应自动更新:

Populated data table

那真是个单位! 如果你有一切工作,现在就马上做一个胜利圈。 真的,你应得的!

在本单元中,我们了解了数据表和表单组件,然后使用远程对象将它们连接到实际数据。 然而,这里缺少的东西不是吗? 我们已经有了一个闪电式的桌子,但是有点儿单调乏味。 该网页真的需要一些图标和图像来活跃起来,你不觉得吗? 在下一节中,我们将给你的页面设计TLC值得。

Lightning-设计(3)网格系统

学习目标

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

  • 描述网格系统组件如何工作。
  • 使用网格系统布局对象主页/列表视图页面。

什么是网格系统?

除了最简单的页面和组件外,其他所有的基础都是某种布局网格。设计系统为此目的提供了一个专门的组件,这个目的被称为网格系统。如果您使用了其他CSS框架(如Bootstrap),则您将熟悉网格的概念。如果没有,非常简短地说,一个网格允许你把你的页面分成行和列。然后,您可以安排您的标记,使其呈现在特定的行/列中。网格可以嵌套,以实现复杂的布局。

设计系统网格基于CSS Flexbox,并提供灵活的,移动优先的,设备无关的脚手架系统。设计系统还包含助手类,可以用来改变网格的外观和行为,例如对齐,顺序,流动和填充。

网格系统允许您通过为小型,中型和大型屏幕定义特定布局变体来创建响应式页面。这些分别定义为480px,768px和1024px的断点。裁剪响应式页面的细节超出了本教程的范围,但如果您想了解更多信息,请参阅尺寸实用工具页面文档。

如何使用网格系统

网格系统基于两个关键构建块:网格包装(用slds-grid类指定)和其中的列(用slds-col类指定)。这是一个例子:

要开始,将slds-grid类添加到外部包装器元素。然后在里面添加所需数量的列,通过添加slds-col类到子元素。在这种情况下,我们将使用<div>元素。例如,这是一个简单的三列网格:

<div class="slds-grid">
  <div class="slds-col">Column 1</div>
  <div class="slds-col">Column 2</div>
  <div class="slds-col">Column 3</div>
</div>
这个标记导致以下布局:

Sample easy grid

默认情况下,列的大小与其内容相关。在这个简单的例子中,我们应该看到三个相同间距的列,因为它们拥有相同数量的内容。如果更多的内容被添加到其中一列,它会相对于其他内容增长。

您还可以使用大小助手类来手动指定列的大小。这些使用slds-size-X-Y格式,其中X表示总空间Y的一部分。例如,slds-size-1-2表示宽度为可用空间的50%。使用手动调整大小等级帮助程序,您可以在以下网格中指定列比率 – 2,3,4,5,6和12。

这是修改上面的例子,以便第一列填充屏幕的三分之二。

<!--  基本网格示例-->
<div class="slds-grid">
  <div class="slds-col slds-size--4-of-6">Column 1</div>
  <div class="slds-col slds-size--1-of-6">Column 2</div>
  <div class="slds-col slds-size--1-of-6">Column 3</div>
</div>

Columns in 4:1:1 width ratio

大小助手也可以用来根据屏幕大小指定不同的布局。例如,让我们创建一个两列网格,其中两列是:

  • 全宽,并垂直排列在手机屏幕上
  • 大小为1:1,并排排列在小屏幕上(> 480像素)
  • 大小为3:1,并排放置在较大的屏幕上(> 768像素)

Responsive example

这里是相应的标记:

<!-- 响应网格示例 -->
<div class="slds-grid slds-wrap">
  <div class="slds-col slds-size--1-of-1 slds-small-size--1-of-2 slds-medium-size--3-of-4">A</div>
  <div class="slds-col slds-size--1-of-1 slds-small-size--1-of-2 slds-medium-size--1-of-4">B</div>
</div>

使用这种移动优先方法,您可以在需要的特定断点处控制元素宽度。没有更多的移动页面破碎!

我们只涉及到网格的基础知识。有关网格的更多文档,请参阅Design System网站上的网格系统和尺寸页面。现在到一些代码!

创建页眉

我们来创建一个列表视图页面。我确信你在Salesforce中看到过他们。以下线框显示了我们的目标:

  • 顶部标题,适当地摆放
  • 主列表区
  • 底部页脚

List view wireframe

使用以下代码创建一个名为Trailhead_SLDS_Listview的新Visualforce页面:

<apex:page showHeader="false" standardStylesheets="false" sidebar="false" applyHtmlTag="false" applyBodyTag="false" docType="html-5.0">

<html xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" lang="en">
<head>
  <meta charset="utf-8" />
  <meta http-equiv="x-ua-compatible" content="ie=edge" />
  <title>Salesforce Lightning Design System Trailhead Module</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />

  <!-- 导入设计系统样式表 -->
  <apex:slds />
</head>
<body>

  <!-- 需要的SLDS包装 -->
  <div class="slds-scope">

    <!-- MASTHEAD -->
    <p class="slds-text-heading--label slds-m-bottom--small">
      Salesforce Lightning Design System Trailhead Module
    </p>
    <!-- / MASTHEAD -->

    <!-- PAGE HEADER -->
    <!-- / PAGE HEADER -->

    <!-- PRIMARY CONTENT WRAPPER -->
    <div class="myapp">
    </div>
    <!-- / PRIMARY CONTENT WRAPPER -->

    <!-- FOOTER -->
    <!-- / FOOTER -->

  </div>
  <!-- / 需要的SLDS包装 -->

  <!-- JAVASCRIPT -->
  <!-- / JAVASCRIPT -->
</body>
</html>
</apex:page>
这是我们的列表视图页面的骨架大纲。现在我们将通过添加页眉组件来使事情变得更加有趣。这个组件有一堆新的标记和类,但不用担心,我们将在下面进行介绍。用下面的代码替换标记中的<! – PAGE HEADER – >部分:
<!-- PAGE HEADER -->
<div class="slds-page-header" role="banner">
  <div class="slds-grid">
    <div class="slds-col slds-has-flexi-truncate">
      <!-- HEADING AREA -->
      <p class="slds-text-title--caps slds-line-height--reset">Accounts</p>
      <h1 class="slds-page-header__title slds-truncate" title="My Accounts">My Accounts</h1>
      <!-- / HEADING AREA -->
    </div>
    <div class="slds-col slds-no-flex slds-grid slds-align-top">
      <button class="slds-button slds-button--neutral">New Account</button>
    </div>
  </div>
  <div class="slds-grid">
    <div class="slds-col slds-align-bottom slds-p-top--small">
      <p class="slds-text-body--small page-header__info">COUNT items</p>
    </div>
  </div>
</div>
<!-- / PAGE HEADER -->
如果你现在预览你的页面,你会看到列表视图页面开始开始,而且是顶部。现在是问自己一个好时机:“我必须写多少CSS才能创建这个美丽风格的页眉组件?

List view with header complete

由于这是更高级的设计系统组件之一,我们将逐行进行。我们建议您在我们经历的时候,在您最喜欢的开发环境中打开您的源代码:

外部包装器<div>具有应用页面标题样式的类slds-page-header。里面我们有一个两列的Grid System。

第一个网格列包含两个元素,其中一个具有文本标题实用程序类,而另一个具有特定于组件的CSS类slds-page-header__title。

第二栏涉及更多一点。它有多个应用的​​类:slds-col slds-no-flex slds-grid slds-align-top。 slds-no-flex是设计系统布局实用程序类之一,并通过删除其flex属性来防止列自动调整大小。 slds-align-top是一个对齐工具类,用于调整列内容的垂直位置,使其与顶部对齐。

在第二列中,我们有一个Button组件,它有一个修饰符类,slds-button-neutral,它应用最小的样式。

在网格下面,页面标题的第二行是一个简单的占位符,用于列表视图中项目数的计数。

填写列表视图轮廓的其余部分

接下来,我们将添加一个简单的无序列表作为光荣的数据表的即将到来的占位符。用下面的代码替换标记中的<! – PRIMARY CONTENT WRAPPER – >部分:

<!-- PRIMARY CONTENT WRAPPER -->
<div class="myapp">

  <ul class="slds-list--dotted slds-m-top--large">
    <li>Account 1</li>
    <li>Account 2</li>
    <li>Account 3</li>
    <li>Account 4</li>
    <li>Account 5</li>
    <li>Account 6</li>
    <li>Account 7</li>
    <li>Account 8</li>
    <li>Account 9</li>
    <li>Account 10</li>
  </ul>

</div>
<!-- / PRIMARY CONTENT WRAPPER -->
预览页面,你会看到基本的列表视图布局采取的形式:

List view with layout complete

默认情况下,内容将填充屏幕宽度。如果您希望将主要内容在屏幕上水平放置或将其限制在特定宽度,请使用slds-container – * helper类之一。

设计系统样式应用于带有slds-list-dotted和slds-m-top-large类的<ul>。无可否认,这不是很令人兴奋的主要内容,只是等到下一个单位…

让我们暂且放一下。设计系统的重点是作为一个“应用程序框架”,而不是“网页框架”。为此,我们避免在默认情况下添加额外的样式。相反,开发人员可以选择手动添加其他样式,例如在本例中。这使开发人员能够更好地控制确切的布局,并且在空间有限的情况下可以产生很大的影响。在您了解设计系统时,您将会看到很多其他组件(如Button)中的默认样式假设。

要完成我们的列表视图布局框架,我们将使用另一个Grid System组件添加页脚。你现在应该成为这方面的专家!我们使用一些额外的修饰符类:

  • slds-p-around – large为页脚元素添加填充
  • slds-grid – align-spread展开主轴上的网格列,第一列从最左边开始,最后一个结束于最右边。

这里是<! – FOOTER – >评论之间的页脚标记:

<!-- FOOTER -->
<footer role="contentinfo" class="slds-p-around--large">
  <!-- LAYOUT GRID -->
  <div class="slds-grid slds-grid--align-spread">
    <p class="slds-col">Salesforce Lightning Design System Example</p>
    <p class="slds-col">&copy; Your Name Here</p>
  </div>
  <!-- / LAYOUT GRID -->
</footer>
<!-- / FOOTER -->
预览您的页面,您可以看到正在形成的列表视图。再次注意,我们不需要编写任何CSS来给我们提供最新的Lightning UI样式。我们所要做的就是在我们的HTML标记中应用Design System类。在下一个单元中,我们将钩住一些真实的数据。

List view with layout complete

最后一个注意事项:请记住,网格系统可能并不总是实现特定布局的最佳组件。例如,如果您想要并排显示图像和文本,则只需使用“媒体对象”或“拼贴”组件可能会更简单。

Lightning-设计(2)开始

学习目标

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

  • 使用Design System设计一个基本的Visualforce页面。
  • 描述设计系统的类结构和块元素修饰符(BEM)语法。

创建一个首页

在本模块其余部分的过程中,我们将使用设计系统构建Visualforce页面。让我们创建第一个Visualforce页面并包含设计系统。然后,我们将通过测试页面来解释设计系统的类结构。

进入安装程序,然后为“页面”快速查找,创建一个Visualforce页面。完成表格如下:

  • 标签: Trailhead_SLDS_Basic
  • 名称: 应该自动默认为 Trailhead_SLDS_Basic
<apex:page showHeader="false" standardStylesheets="false" sidebar="false" applyHtmlTag="false" applyBodyTag="false" docType="html-5.0">

<html xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" lang="en">
<head>
  <meta charset="utf-8" />
  <meta http-equiv="x-ua-compatible" content="ie=edge" />
  <title>Salesforce Lightning Design System Trailhead Module</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />

  <!-- 导入设计系统样式表-->
  <apex:slds />
</head>
<body>

  <!--  需要的SLDS包装-->
  <div class="slds-scope">

    <!-- MASTHEAD -->
    <p class="slds-text-heading--label slds-m-bottom--small">
      Salesforce Lightning Design System Trailhead Module
    </p>
    <!-- / MASTHEAD -->

    <!-- PRIMARY CONTENT WRAPPER -->
    <div class="myapp">

      <!-- 部分 - 徽章组件 -->
      <section aria-labelledby="badges">
        <h2 id="badges" class="slds-text-heading--large slds-m-vertical--large">Badges</h2>
        <div>
          <span class="slds-badge">Badge</span>
          <span class="slds-badge slds-theme--inverse">Badge</span>
        </div>
      </section>
      <!-- / SECTION - BADGE COMPONENTS -->

    </div>
    <!-- / PRIMARY CONTENT WRAPPER -->

  </div>
  <!-- / 需要的SLDS包装 -->

</body>
</html>
</apex:page>
如果您现在预览您的页面,您应该看到以下内容:

Basic demo page

看起来像新的闪电设计,而不必自己写任何CSS。相当漂亮,是吧?

哦,不要为这些徽章数量太多而感到兴奋。他们是设计系统的组件,而不是Trailhead徽章!我们很乐意帮助你创造自己的,但是Trailhead警察会感到不安。

虽然这个例子非常简单,但它引入了很多设计系统的概念。在进入更多令人兴奋的布局之前,我们会对这些进行评估

与所有Visualforce页面一样,标记的外层包装是<apex:page>元素。

在你的html标签上,一定要包含xmlns =“http://www.w3.org/2000/svg”xmlns:xlink =“http://www.w3.org/1999/xlink”属性。这对于在Visualforce中启用对SVG图标精灵贴图的支持非常重要。注意:我们的示例显示标题,侧栏和内置样式表已关闭。目前,如果您需要使用Salesforce标题或侧栏,则无法在<html>元素上指定额外的属性。在这种情况下,不支持SVG图标。

在我们的<head>部分,我们使用<apex:slds />导入设计系统,它将加载文档中的CSS。

现在进入包含我们的第一个设计系统标记的<body>标签。我们将一行一行地通过它。由于有相当多的事情发生,我们建议在您最喜欢的编辑器中同时打开页面。我们走吧。

每次在Visualforce中使用“设计系统”标记时,都应将其放在具有slds-scope作用域类的外部包装器<div>中。每次。无论您是否拥有Visualforce标题并留下导航,或者不是。得到它了?它会在稍后的测验中。

接下来我们有一个简单的桅杆头标签,其中应用了两个设计系统类。首先,slds-text-heading – 标签应用文本标题样式。第二个类slds-m-bottom-small是一个间隔工具类,用于在标题下添加一些填充。你可能会问这些疯狂的类名是什么?这是双下划线错字?继续阅读,所有将被解释。

在<section>元素中,我们有另一个标题,这次是<h2>,用slds-m-vertical-large spacing工具类来添加顶部和底部填充。

您可能会惊讶于需要明确添加此垂直填充。重要的是要记住,设计系统侧重于应用程序的构建,而不是布置网页。因此,从排版中删除了默认页边距,以便应用程序生成器可以精确地指定他们需要的内容。

最后,我们看到我们的第一个真正的设计系统组件,一个徽章组件。其实有两个,但是谁在计数?每个通过将一个slds-badge类应用到span元素来创建。第二个徽章有一个slds主题 – 逆主题实用程序类,以反转配色方案。请注意如何将多个Design System类应用于同一个元素以逐步自定义它。在这种情况下应用徽章样式,然后反转颜色。稍后你会在模块中看到更多的内容。

这里的所有都是它的!布置你的标记,并应用相应的设计系统类为最新的闪电视觉设计。看马,没有CSS!

所有的设计系统类都记录在设计系统网站上。

Badge documentation

SLDS类命名

在我们继续之前,让我们先谈谈在Design System类名称中提到的那些双连字号。我们的CSS使用一个叫做块元素修饰语法(BEM)的标准类命名约定来使得类名不那么含糊:

  • 块表示高级组件(例如.car)
  • 元素表示组件的后代(例如.car_door)
  • 修饰符表示块或元素的特定状态或变体(例如,车门 – 红色)

现在炙手可热的问题,为什么双连字符和下划线?首先,他们可以更容易地看到CSS规则正在被应用(通过分离出块/元素和修饰符)。而且,使用双精度而不是单个连字符和下划线表示块或修饰符本身可以包含连字符或下划线,例如.slds-button__icon-x-small。给它一个去,我们认为你会发现它一样有用,因为我们一旦你习惯了。

Lightning-设计(1)

学习目标

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

  • 描述Salesforce Lightning设计系统是什么以及它的用途。
  • 描述设计系统所依据的关键设计原则。

介绍闪电设计系统

Salesforce用户体验团队一直在努力将Enterprise UX推向21世纪,并为能够提供Lightning设计系统而感到自豪。设计系统使您可以轻松构建符合新Salesforce Lightning外观的应用程序,而无需将UI反向设计为自定义CSS。实际上,使用新的设计系统标记会导致在没有编写任何CSS的情况下具有Lightning外观和感觉的页面。感兴趣吗?激动吗?我们是!阅读。

Lightning Design System website

闪电设计系统是相当的一口,所以我们在这里称之为“设计系统”。

您可能使用了其他类似的设计系统,例如Twitter Bootstrap或Foundation来构建网站。这个设计系统的主要好处是:

  • 它是为构建Salesforce应用程序而量身定制的。使用Design System标记和CSS框架会生成反映Salesforce Lightning外观的UI。关注构建应用程序是一个重要的记住。设计系统不会过度执行诸如填充和边距之类的默认设置,而其他一些框架则专注于构建营销页面。设计系统可让您轻松指定所需的确切布局,同时符合新的Lightning UI。
  • 它不断更新。只要您使用的是最新版本的设计系统,您的页面就会始终与Salesforce UI更新保持同步。
  • 辅助功能被烘焙到组件背后的CSS框架中。
  • CSS完全由slds-前缀命名,并且使用slds-scope类作用域以避免CSS冲突。

设计系统捆绑了四种类型的资源来帮助您构建应用程序。

  • CSS framework — 定义UI组件,例如页面标题,标签和表单元素,网格布局系统和单一用途的帮助程序类,以帮助进行间距,大小调整和其他视觉调整。
  • Icons — 包括我们的动作,自定义,文档类型,标准和实用程序图标的PNG和SVG(包括个人和spritemap)版本。
  • Font — 印刷术是我们产品的核心。我们从头开始设计了全新的Salesforce Sans字体,为我们的产品提供独特的视觉语音和个性,并将其作为设计系统的一部分提供给您。
  • Design Tokens — 这些设计变量允许您调整视觉设计的各个方面以匹配您的品牌。可定制的变量包括颜色,字体,间距和大小。

设计系统围绕现代浏览器的功能而构建,并具有一些最低限度的浏览器要求。 Chrome,Safari和Firefox的现代版本已经过全面测试。对于Microsoft Internet Explorer(MSIE),Design System仅支持版本11和Microsoft Edge。早期版本的MSIE的用户可能会遇到诸如缺少图标等问题。

核心设计原则

设计系统代表的Lightning Experience UI是使用四个核心设计原则制作的。我们鼓励您在开发应用程序时记住它们。

  • 清晰 —消除歧义。使人们有信心地看到,理解和行动。新的用户界面减少了混乱,使用户可以很容易地找到他们需要的信息。
  • 效率— 简化和优化工作流程。智能地预测需要帮助人们更好,更聪明,更快地工作。例如,新的Lightning用户界面按钮可以改善行动号召力。
  • 一致性 — 通过对相同的问题应用相同的解决方案,创造熟悉性并增强直觉。例如,新UI在所有上下文中强制执行一个按钮样式。
  • 美丽 — 通过周到和优雅​​的工艺,展现对人们时间和关注的尊重。一个UI可以美丽吗?我们这么认为!

你可以在哪里使用设计系统

新的设计系统使得在一系列技术堆栈中构建符合Lightning的Salesforce应用程序变得简单易行。

  • Visualforce pages 通过远程对象或JavaScript远程访问来访问Salesforce数据。设计系统还不兼容<apex>标签,但请留意这个空间。
  • Lightning pages and components 可用于Salesforce1和Lightning Experience
  • Mobile apps 通过Mobile SDK或其他API访问Salesforce
  • Standalone web apps Heroku或类似平台提供

模块先决条件

该模块的其余部分包括一些有趣的手动技术工作。在您进入之前,请查看以下先决条件:

  • 您必须有权访问Salesforce开发者帐户。
  • 示例页面假设您具有Web开发(HTML,CSS,JavaScript)和Salesforce管理的一些知识。
  • 该模块着重于使用Visualforce页面中的设计系统,因此有一定的技术经验是有益的。 但是,尽管代码示例是特定于Visualforce的,但您可以在其他堆栈中重复使用它们,但只需进行较小的自定义操作。

Lightning-覆盖标准按钮(5)

现在我们已经成功地重写了New按钮,只需要一点点工作,我们也可以重用组件来覆盖Edit按钮。这实际上有点愚蠢,因为当我们覆盖Edit按钮时,它也禁用标准记录页面的内联编辑能力。这意味着我们永远无法编辑对话框中的五个字段。但是,让我们这样做,因为它可能在另一个环境中有用。

创建代码来处理上下文

  1. 在Developer Console中,切换到PropertyDialog组件。
  2. 在force之前的新行上添加新的aura:属性:recordData:
    <aura:attribute name="modalContext" type="String" default="New" />
    
  3. 将作为模式标题的<h2>标签更改为:
    <h2 class="slds-text-heading--medium">{!v.modalContext} Record</h2>
    

    通过将标题的上下文定义为aura:属性,当模式用于编辑记录时,我们可以轻松地将其从“新建”更改为“编辑”。

  4. 切换到PropertyDialogController。
  5. 在doInit:function(component,event,helper){下面添加一个新行{并添加下面的代码:
    var recId = component.get("v.recordId");
    if (recId) {
        component.set("v.modalContext", "Edit");
    }
    
  6. 在if语句中包装函数的其余部分:
    if (!recId) {
        component.find("forceRecord").getNewRecord(
            "Property__c",
            null,
            false,
            $A.getCallback(function() {
                var rec = component.get("v.propertyRecord");
                var error = component.get("v.recordError");
                if (error || (rec === null)) {
                    console.log("Error initializing record template: " + error);
                    return;
                }
            })
        ); 
    }
    
    现在,当组件加载时,它检查recordId的存在。当然,当它与New按钮一起使用时,没有recordId;因此,该功能创建新的记录。但是,如果recordId存在,modalContext属性设置为Edit。
  7. 保存这两个文件。

预填充字段

当我们使用对话框编辑记录时,我们显然需要当前的字段值已经在对话框中(你不能编辑你看不到的东西)。

  1. 切换回PropertyDialog组件。
  2. 添加 value="{!v.propertyRecord.Name}"value="{!v.propertyRecord.Beds__c}"value="{!v.propertyRecord.Baths__c}", 和 value="{!v.propertyRecord.Price__c}" 到相应的lightning:input 标签.
  3. 添加 value="{!v.propertyRecord.Status__c}" 到 lightning:select.

    你的代码应该是这样的:

    <lightning:input aura:id="propName" name="propName" label="Property Name" value="{!v.propertyRecord.Name}" required="true" class="slds-size--1-of-1 slds-p-horizontal_x-small" />
    <lightning:input aura:id="propBeds" name="propBeds" label="Beds" value="{!v.propertyRecord.Beds__c}" class="slds-size--1-of-2 slds-p-horizontal_x-small" />
    <lightning:input aura:id="propBaths" name="propBaths" label="Baths" value="{!v.propertyRecord.Baths__c}" class="slds-size--1-of-2 slds-p-horizontal_x-small" />
    <lightning:input aura:id="propPrice" name="propPrice" label="Price" value="{!v.propertyRecord.Price__c}" class="slds-size--1-of-2 slds-p-horizontal_x-small" />    
    <lightning:select aura:id="propStatus" name="propStatus" label="Status" value="{!v.propertyRecord.Status__c}" class="slds-size--1-of-2 slds-p-horizontal_x-small">
        <aura:iteration items="{!v.picklistValues}" var="item">
            <option value="{!item}">{!item}</option>
        </aura:iteration>
    </lightning:select>
    
  4. 保存文件。

更新取消按钮

在财产记录页面上,当用户点击取消按钮,现在他们重新回到属性列表页面。让我们改变这一点,以便用户最终在财产记录页上。

  1. 切换回PropertyDialogController。
  2. 用以下代码替换cancelDialog函数:
    cancelDialog: function(component, event, helper) {
        var recId = component.get("v.recordId");
        if (!recId) {
            var homeEvt = $A.get("e.force:navigateToObjectHome");
            homeEvt.setParams({
                "scope": "Property__c"
            });
            homeEvt.fire();
        } else {
            helper.navigateTo(component, recId);
        }
    }
    
    再一次,我们检查一下recordId是否存在。如果是这样,我们知道我们正在一个记录页面,并将返回到该页面。
  3. 保存文件。
  4. 切换回您的组织并单击替代文本:设置图标alt text: Setup Icon并选择 Setup
  5. 点击 Object Manager.
  6. 点击 Property.
  7. 点击 Buttons, Links, and Actions.
  8. 点击 alt text: Dropdown menu icon 然后选择编辑。
  9. 选择覆盖 Lightning Component Bundle.
  10. 选择 c:PropertyDialog 作为要覆盖的包,然后单击保存。
  11. 点击应用启动器图标alt text: App Launcher icon,然后选择Dreamhouse Lightning。
  12. 单击“属性”,然后单击任何属性名称以导航到其属性记录页面,然后刷新此页面。
  13. 单击编辑按钮以在记录页面的上下文中测试对话框。

高五分! 正如你刚刚学到的,使用Lightning组件覆盖标准动作和按钮是非常容易的。 当然,这样做有一些考虑,但这个过程本身是非常简单的。 现在,去超越!

Lightning-覆盖标准按钮(4)

我们终于到了!现在是时候将我们新的Lightning组件用作标准按钮覆盖。这实际上很简单,几乎可以用你创建的任何Lightning组件完成。有几个考虑因素,但我们很快就会解决。

添加覆盖界面

  1. 在您的组织的财产记录页面上,单击替代文本:设置图标alt text: Setup Icon,然后选择 Edit Page.
  2. 点击我们新的Lightning组件选择它,然后点击alt text: Delete component:删除组件将其从页面中删除。
  3. 单击保存,然后单击返回返回到您的属性详细信息页面。

    现在,我们准备将该组件用作按钮覆盖,因此不必再将其放在页面上。

  4. 在Developer Console中,切换回PropertyDialog组件。
  5. 将lightning:actionOverride添加到aura:component标签中的接口列表中。它现在应该是这样的:
    <aura:component implements="flexipage:availableForRecordHome,force:hasRecordId,lightning:actionOverride" access="global" >
    
  6. 保存文件。

    lightning:actionOverride 是神奇的界面,指示Lightning Experience让我们使用这个组件来覆盖标准的按钮或动作。

设置覆盖

  1. 回到您的组织中,单击alt text: Setup Icon:设置图标并选择设置。
  2. 点击 Object Manager.
  3. 点击 Property.
  4. 点击 Buttons, Links, and Actions.
  5. 点击 alt text: Dropdown menu icon 旁边的新建,然后选择 Edit.
  6. 选择覆盖 Lightning Component Bundle.
  7. 选择c:PropertyDialog作为要用其覆盖的包。

    alt text: Override with Lightning Component

    选择列表将列出组织中具有闪电:actionOverride接口声明的所有组件。

  8. 点击 Save.
  9. 点击 alt text: App Launcher icon 然后选择Dreamhouse闪电,然后点击属性。
  10. 刷新此页面,然后单击新建以创建新的属性。

    就在那里!您已使用Lightning组件覆盖了Property对象上的标准New按钮。

    注意:如果您没有看到新的表单,则可能需要重新刷新页面。单击属性,刷新页面,然后单击新建。

将SLDS样式添加到我们的闪电组件

朋友之间,你不得不承认,组件不是很漂亮。当您使用Lightning组件作为覆盖时,它会填充整个页面。所以让我们来添加一点SLDS魔术,让它看起来更好。

  1. 在Developer Console中,将PropertyDialog组件的整个代码替换为:
    <aura:component implements="lightning:actionOverride,flexipage:availableForRecordHome,force:hasRecordId" access="global">
        <aura:attribute name="picklistValues" type="Object" />
        <aura:attribute name="propertyRecord" type="Property__c" />
        <force:recordData aura:id="forceRecord"
                          recordId="{!v.recordId}"
                          targetFields="{!v.propertyRecord}"
                          fields="Id,Name,Beds__c,Baths__c,Price__c,Status__c"
                          mode="EDIT" />
        <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    
        <c:PickListValues sObjectName="Property__c" fieldName="Status__c" picklistValues="{!v.picklistValues}" />
    
        <div aura:id="editDialog" role="dialog" tabindex="-1" aria-labelledby="header43" class="slds-modal slds-fade-in-open">
            <div class="slds-modal__container">
                    <div class="slds-modal__header">
                        <h2 class="slds-text-heading--medium">New Record</h2>
                </div>
                <div class="slds-modal__content slds-p-around--medium slds-grid slds-wrap ">
                    <lightning:input aura:id="propName" name="propName" label="Property Name" required="true" class="slds-size--1-of-1 slds-p-horizontal_x-small" />
                    <lightning:input aura:id="propBeds" name="propBeds" label="Beds" class="slds-size--1-of-2 slds-p-horizontal_x-small" />
                    <lightning:input aura:id="propBaths" name="propBaths" label="Baths" class="slds-size--1-of-2 slds-p-horizontal_x-small" />
                    <lightning:input aura:id="propPrice" name="propPrice" label="Price" class="slds-size--1-of-2 slds-p-horizontal_x-small" />    
                    <lightning:select aura:id="propStatus" name="propStatus" label="Status" class="slds-size--1-of-2 slds-p-horizontal_x-small">
                        <aura:iteration items="{!v.picklistValues}" var="item">
                            <option value="{!item}">{!item}</option>
                        </aura:iteration>
                    </lightning:select>
                </div>
                <div class="slds-modal__footer">                
                    <lightning:button variant="neutral" label="Cancel" />
                    <lightning:button variant="brand" label="Submit" onclick="{!c.saveRecord}" />
                </div>
            </div>
        </div>
        <div aura:id="overlay" class="slds-backdrop slds-backdrop--open"></div>
    </aura:component>
    
    使用Salesforce Lightning Design System中模式的标记使页面看起来更好。
  2. 保存文件。
  3. 在您的组织中,刷新属性页面以查看新模型。如果您不在表单上,​​然后单击新建以查看它。

alt text: New record dialog

现在看起来不太好?

启用取消按钮

  1. 在开发人员控制台的PropertyDialog组件中,将onclick处理程序onclick =“{!c.cancelDialog}”添加到“取消”按钮。
  2. 保存文件。
  3. 切换到PropertyDialogController并添加以下代码以创建一个新的cancelDialog函数,该函数将组件和帮助器作为参数(不要忘记逗号):
    cancelDialog : function(component, helper) {
    }
    
  4. 添加以下功能:
    var homeEvt = $A.get("e.force:navigateToObjectHome");
    homeEvt.setParams({
        "scope": "Property__c"
    });
    homeEvt.fire();
    
    与我们创建的navigateTo函数类似,此函数只是调用navigateToObjectHome事件,将用户发送回主“属性”页面。
  5. 保存文件。
  6. 在您的组织中,刷新属性页面,然后单击取消。

    你回到属性首页。

Lightning-覆盖标准按钮(3)

当从Visualforce世界转移到Lightning组件时,开发人员面临的一个重大变化是如何与服务器通信。直到Summer ’17发布,这意味着创建一个Apex类来做任何事情,甚至是在Visualforce中“自动”处理的简单的CRUD交互。随着夏季’17发布和闪电数据服务的引入,这一切都改变了。因此,对于我们的组件,我们使用Lightning Data Service创建新的属性记录 – 无需编写Apex!

添加force:recordData

  1. 在开发人员控制台的PropertyDialog组件中,在刚添加的aura:attribute和c:PickListValues之间添加以下内容:
    <aura:attribute name="propertyRecord" type="Property__c" />
    <force:recordData aura:id="forceRecord"
                    recordId="{!v.recordId}"
                    targetFields="{!v.propertyRecord}"
                    fields="Id,Name,Beds__c,Baths__c,Price__c,Status__c"
                    mode="EDIT" />
    

    Lightning Data Service使用名为force:recordData的对象在记录上执行CRUD交互。 force有几个其他的属性:recordData,但是为了我们的目的,我们只需要recordId,targetRecord,fields和mode。

    当值被分配给recordId属性时,在场景后面,Lightning Data Service将检索整个记录或请求的字段。结果字段存储在由targetFields属性定义的属性中;在这种情况下,propertyRecord。最后,mode属性定义了force:recordData的这个实例是处于VIEW模式还是EDIT模式。显然,由于我们正在创建一个记录,它需要处于编辑模式。

初始化新记录

  1. 在force之后的新行添加以下内容:recordData标记:
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    
  2. 单击侧面导航中的“控制器”以将控制器添加到组件。
  3. 将默认函数myAction重命名为doInit,并将以下内容添加到函数中:
    component.find("forceRecord").getNewRecord(
            "Property__c",
            null,
            false,
            $A.getCallback(function() {
                var rec = component.get("v.propertyRecord");
                var error = component.get("v.recordError");
                if (error || (rec === null)) {
                    console.log("Error initializing record template: " + error);
                    return;
                }
            })
        );
    
    强制的getNewRecord:recordData有四个参数。第一个参数Property__c定义要创建记录的sObject的实体API名称。下一个参数是recordTypeId。我们将其设置为空,它只是说根据用户的配置文件使用默认的记录类型。第三个参数决定是否从客户端缓存加载记录模板。最后,回调检查是否有错误或者propertyRecord属性是否未被填充。

保存新记录

  1. 在PropertyDialogController中添加一个名为saveRecord的新函数,并传递组件,事件,帮助器作为参数:
    saveRecord : function(component, event, helper) {
    }
    
    不要忘记逗号分隔功能!
  2. 将以下内容添加到新功能中:
    var propBeds = parseInt(component.find('propBeds').get("v.value"), 10);
    var propBaths = parseInt(component.find('propBaths').get("v.value"), 10);
    var propPrice = parseInt(component.find('propPrice').get("v.value"), 10);
    
    component.set("v.propertyRecord.Name", component.find('propName').get("v.value"));    
    component.set("v.propertyRecord.Beds__c", propBeds);
    component.set("v.propertyRecord.Baths__c", propBaths);
    component.set("v.propertyRecord.Price__c", propPrice);
    component.set("v.propertyRecord.Status__c", component.find('propStatus').get("v.value"));
    
    var tempRec = component.find("forceRecord");
    tempRec.saveRecord($A.getCallback(function(result) {
        console.log(result.state);
        var resultsToast = $A.get("e.force:showToast");
        if (result.state === "SUCCESS") {
            resultsToast.setParams({
                "title": "Saved",
                "message": "The record was saved."
            });
            resultsToast.fire();                
        } else if (result.state === "ERROR") {
            console.log('Error: ' + JSON.stringify(result.error));
            resultsToast.setParams({
                "title": "Error",
                "message": "There was an error saving the record: " + JSON.stringify(result.error)
            });
            resultsToast.fire();
        } else {
            console.log('Unknown problem, state: ' + result.state + ', error: ' + JSON.stringify(result.error));
        }
    }));
    

    当我们保存记录时,我们确保字段类型的值是正确的。 Beds__c,Baths__c和Price__c都被设置为Property_c对象中的整数。因此,当我们从输入中获取值时,我们使用parseInt JavaScript方法将其从一个字符串转换为一个整数。一旦转换,我们更新propertyRecord属性中的值以及来自其他表单字段的值。

    接下来,我们使用tempRec的变量赋值来调用saveRecord的force:recordData方法,以将记录的新值保存回Salesforce。哦,我们是否提到过那是?真的,tempRec.saveRecord(),我们完成了!

    当然,在saveRecord方法的回调中还有更多。确保记录成功保存后,我们吐出一杯祝酒词,让用户知道保存是否奏效。

  3. 保存PropertyDialogController.js并切换回PropertyDialog组件。
  4. onclick="{!c.saveRecord}" 添加到提交对话框的lightning:button   (标签为“submit”的按钮).
  5. 保存文件。

导航到保存后的新记录

记录保存后,我们不希望对话框坐在那里。因此,我们可以选择:导航到“属性”列表或新创建的记录。让我们做一个行政决定,并导航到新创建的记录。

  1. 在开发人员控制台中,单击侧面导航栏中的“助手”以将助手文件添加到组件。

    当您最初开始构建Lightning组件时,将所有JavaScript函数放在控制器文件中感觉很自然。但是,在控制器文件中,不能从另一个函数调用一个函数。所以,在我们的例子中,如果我们构建了一个导航到记录的函数,我们不能从saveRecord函数中调用它。这意味着我们必须将整个功能写入saveRecord函数。这很糟糕 – 这可能会导致我们在稍后的函数中重复我们的代码。因此,将任何可能需要调用多次或从另一个函数中调用的任何东西放到帮助程序文件中是一种更好的做法。

  2. 将帮助程序文件的默认内容替换为:
    ({
        navigateTo: function(component, recId) {
            var navEvt = $A.get("e.force:navigateToSObject");
            navEvt.setParams({
                "recordId": recId
            });
            navEvt.fire();
        }
    })
    
    这个函数只是调用内置的平台事件force:navigateToSObject,传递我们从recordSave的回调中得到的recordId。
  3. 保存文件。
  4. 切换回PropertyDialogController.js。
  5. 在resultsToast.fire()之后的新行中添加以下内容:在回调的成功状态(在第40行附近):
    var recId = result.recordId;
    helper.navigateTo(component, recId);
    
  6. 保存文件,然后返回到您的组织并刷新属性详细信息页面。
  7. 用这些值填写表单:
    • Name: 123 Main St.
    • Beds: 4
    • Baths: 3
    • Price: 500000
    • Status: Pre-Market
  8. 点击提交。

alt text: The record was successfully saved.

你印象深刻吗?你只是保存了一个新的记录而不用写任何Apex代码去做!即使你是一个性格开朗的开发者,也会觉得非常神奇。接下来,让我们完成我们设定的操作并覆盖“新建”按钮。

Lightning-覆盖标准按钮(2)

通常,当我们考虑Lightning组件时,我们会考虑Lightning Experience中页面上的元素。换句话说,我们想到了前端设计 – 用户在页面上的交互。但是我们也可以构建根本没有任何前端标记的Lightning组件。但是你可能在想,为什么有人会那样做呢?因为我们也可以使用Lightning组件作为可重用的服务或服务组件。

在这一步结束之后,您将会:

  • 了解服务组件的概念
  • 检索选项列表值列表
  • 传递两个组件之间的值

创建闪电组件

  1. 在开发者控制台中,选择 File > New > Lightning Component.
  2. 对于名称,输入: PickListValues 并单击 Submit.

    请注意,我们没有检查任何框,因为我们不打算将这个组件作为一个独立的组件在页面上使用。相反,我们将其用作PropertyDialog组件的子组件,或者将其用作需要选项列表值的任何其他组件的子项。

  3. 将以下内容添加到<aura:component>标记内的组件中:
    <aura:attribute name="sObjectName" type="String" />
    <aura:attribute name="fieldName" type="String" />
    <aura:attribute name="picklistValues" type="Object" />
    
    因为这是一个服务组件,它唯一要做的就是存储一些值。在我们的情况下,我们想知道状态选项列表的值。我们将把它们作为值存储在<aura:attribute name =“picklistValues”/>中。
  4. 保存文件。

检索选项列表值

  1. 在开发者控制台中,点击 File > New > Apex Class.
  2. 命名类: PickListController
  3. 将以下内容添加到 class:
    @AuraEnabled        
    public static List<String> getPickListValuesIntoList(String objectType, String selectedField){
        List<String> pickListValuesList = new List<String>();
        Schema.SObjectType convertToObj = Schema.getGlobalDescribe().get(objectType);
        Schema.DescribeSObjectResult res = convertToObj.getDescribe();
        Schema.DescribeFieldResult fieldResult = res.fields.getMap().get(selectedField).getDescribe();
        List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
        for( Schema.PicklistEntry pickListVal : ple){
            pickListValuesList.add(pickListVal.getLabel());
        }     
        return pickListValuesList;
    }
    
    我们称之为Lightning组件的Apex方法,我们需要使用@AuraEnabled和静态签名。 getPickListValuesIntoList方法接受两个参数,objectType和selectedField。我们将ObjectType变量作为String传递,所以我们把String转换成Object,然后得到它的字段列表。然后我们检索选取列表值,为每个值添加标签,最后返回列表。
  4. 保存文件。

把它连接起来

  1. 在开发者控制台中,切换回PickListValues组件。
  2. 将controller =“PickListController”access =“global”添加到<aura:component>标记。
  3. 在aura属性之后的新行中,将以下内容添加到组件中:
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    
  4. 保存文件。
  5. 单击侧面导航中的“控制器”以将控制器添加到组件。
  6. 将控制器中的代码替换为:
    ({
        doInit : function(component) {
            var action = component.get("c.getPickListValuesIntoList");
            action.setParams({
                objectType: component.get("v.sObjectName"),
                selectedField: component.get("v.fieldName")
            });
            action.setCallback(this, function(response) {
                var list = response.getReturnValue();
                component.set("v.picklistValues", list);
            })
            $A.enqueueAction(action);
        }
    })
    

    这个非常简单的函数调用我们刚刚创建的Apex类的getPickListValuesIntoList方法,然后将它们存储在picklistValues属性中。

  7. 保存文件。

添加服务组件

  1. 在Developer Console中,切换到PropertyDialog组件。
  2. 在打开<aura:component>标记之后添加对PickListValues组件的引用:
    <aura:attribute name="picklistValues" type="Object" />
    <c:PicklistValues sObjectName="Property__c" fieldName="Status__c" picklistValues="{!v.picklistValues}" />
    
    当我们向另一个Lightning组件添加一个子组件时,我们也可以设置子组件中包含的属性。这些值可以是显式定义的,就像我们在这里做的那样,或者是根据绑定到父组件的属性来动态分配的。当Apex类返回值时,我们在子组件中设置picklistValues属性。然后,这个值将起泡到<c:PicklistValues>上的属性定义,该属性定义依次在父组件中设置。啊,数据绑定的美丽!
  3. 将<lightning:select>中的<option value =“status”> Status </ option>替换为:
    <aura:iteration items="{!v.picklistValues}" var="item">
        <option value="{!item}">{!item}</option>
    </aura:iteration>
    
    现在,将使用picklistValues属性中的条目来动态填充<lightning:select>。
  4. 保存该文件,然后刷新组织中的属性记录页面。

    如果一切顺利,而不是“状态”一词,正确的值显示在您的状态选项列表中。

    做得好! 现在我们需要做的就是连接组件,以便能够保存新的属性记录。