Lightning-应用程序(6)

在Visualforce页面中使用Lightning组件

到目前为止,您已经学会了如何使您的Visualforce页面看起来像Lightning Experience,并学习了创建Lightning组件的基础知识。你甚至已经创建了一个很棒的Similar Properties组件。

但是还有最后一件事情要完成,这真是太神奇了。

我们将采用类似的属性组件,并在Visualforce中使用它!是的,你没看错。闪电组件不仅仅是闪电体验。使用闪电,我们可以在任何地方使用闪电组件!

第1部分 – 创建容器应用程序

要在Lightning体验外使用Lightning组件,我们需要将其封装在Lightning应用程序中。闪电应用程序基本上是一个闪电组件,它运行在自己的窗口中,没有典型的Lightning Experience UI(例如全局导航)。事实上,在这个项目中,您已经多次使用了Lightning应用程序。闪电应用程序生成器是一个闪电应用程序!

  1. 在开发者控制台中,点击 New > Lightning Application. 将其命名为SimilarPropertiesApp并选择Lightning Out Dependency App。

    通过选择Lightning Out Dependency App,应用程序实现extends =“ltng:outApp”,它基本上告诉App使用Lightning Out框架。

  2. 为组成SimilarProperties组件的三个组件中的每个组件添加一个依赖关系 – 用以下代码替换缺省代码:
    <aura:application extends="ltng:outApp" >
        <aura:dependency resource="c:SimilarProperties" />
      <aura:dependency resource="c:SimilarProperty" />
        <aura:dependency resource="c:SimilarPropertyEdit" />
        <aura:dependency resource="markup://force:*" type="EVENT"/>
    </aura:application>
    

    我们基本上告诉Lightning应用程序,我们将使用这些Lightning组件。即使其他组件仅包含在SimilarProperties组件中,也包含所有组件。

    我们将该组件添加到Visualforce页面,所以我们需要确保当用户点击属性名称时,我们正在正确处理该记录的导航。这意味着我们需要检测组件是在Lightning Experience页面上使用,正在Lightning Experience中显示的Visualforce页面中使用,还是在Salesforce Classic中的Visualforce页面中使用。

    最后的依赖包括force:namespace中的事件,例如导航事件。当Lightning组件在Lightning Experience中运行时,它将自动访问这些事件。所以我们不必为了在navToRecord函数中调用$ A.get(“e.force:navigateToSObject”)而做任何事情。在Lightning Experience的Visualforce页面中运行的Lightning组件也可以访问这些事件,但语法略有不同。但是,在Salesforce Classic的Visualforce页面中运行Lightning组件时,我们必须使用完全不同的方法来执行导航等操作。

  3. 保存文件。

第2部分 – 更新Visualforce页面

由于我们已经有一个嵌入在Property Record页面中的Visualforce页面,所以我们可以更新标记来使用Similar Properties组件。

  1. 在开发人员控制台中,选择 File > Open Resource, 然后打开“Similar_Properties.vfp”页面。
  2. 更新页面如下:
    <apex:page standardController="Property__c" standardStylesheets="false" applyBodyTag="false">
    
        <style>
            html, body {
            margin: 0;
            padding: 0;
            }
            #lightningComponent {width: 100%;}
        </style>
    
        <div id="content">
            <div id="lightningComponent" />
        </div>
    
    </apex:page>
    
    不要恐慌,但是,你基本上只是摧毁了页面。没关系,因为页面只包含Lightning组件,我们将把这个组件放在带有lightningComponent的id的<div>中。

第3部分 – 在Visualforce页面中加载SimilarProperties组件

  1. 在打开的<apex:page>标签之后立即添加<apex:includeLightning />标签。

    该指令在页面中包含Lightning Out框架。

  2. 在关闭</ apex:page>标记之前立即添加以下JavaScript代码:
    <script>
    var recordId = '{!Property__c.Id}';
    var myUserContext = "{!$User.UITheme}";
    $Lightning.use("c:SimilarPropertiesApp", function() {
        $Lightning.createComponent("c:SimilarProperties",
                                   {recordId: recordId},
                                   "lightningComponent",
                                   function(cmp) {
                                       $A.eventService.addHandler({
                                           event: 'force:navigateToSObject',
                                           handler: function(event) {
                                               if (myUserContext == 'Theme4t' || myUserContext == 'Theme4d') {
                                                   // Visualforce页面位于S1或Lightning Experience中
                                                   sforce.one.navigateToSObject(event.getParams().recordId);
                                               } else if (myUserContext == 'Theme3') {
                                                   // Visualforce页面正在Classic中运行
                                                   window.parent.location = '/' + event.getParams().recordId;
                                               } else {
                                                   console.log("Unsupported theme");   
                                               }
                                           }
                                       });
                                   }
                                  );
    });
    </script>
    

    这是魔术发生的地方!该脚本从标准控制器中检索记录的Id并获取用户的主题,并将其分配给变量。然后$ Lightning.use()指示页面包含您刚刚创建的SimilarPropertiesApp。然后在应用程序中创建SimilarProperties组件的一个实例,将recordId传递给组件,然后将它放在页面中具有lightningComponent的id的<div>中。

    最后,在创建组件之后,我们添加了一个事件处理程序$ A.eventService.addHandler,并将force:navigateToSObject事件声明为我们有兴趣监听的事件。当用户点击组件中的一个Property Name时,脚本拦截对$ A.get(“e.force:navigateToSObject”)的调用并执行定义为该处理程序的函数。这个函数使用脚本第二行定义的myUserContext变量来检测用户的主题。如果用户的主题是Theme4t(Salesforce1)或Theme4d(Lightning Experience),则脚本将使用在Lightning Experience内的Visualforce页面中运行的Lightning Component的正确语法来触发navigateToSObject方法。如果用户的主题是Theme3,则我们知道Classic中的用户,并使用window.parent.location指示页面导航到新页面。

  3. 保存文件。
  4. 刷新“属性记录”页面并向下滚动到“类似属性”部分以查看组件。
    雷电体验类似的属性部分。

    Similar Properties section in Lightning Experience.

    多么酷啊?这是Lightning页面中Visualforce页面中的闪电组件。这是一个Salesforce Turducken!

  5. 单击组件中的“属性名称”以确认导航正在工作。
  6. 点击您的个人资料图片,然后选择切换到Salesforce Classic。
  7. 在最近的项目列表中点击一个属性。
  8. 向下滚动以查看在Salesforce Classic中运行的美丽的Lightning组件!
    Similar Properties section in Salesforce Classic.
  9. 单击组件中的不同Property Name,然后使用脚本中的window.location方法导航到正确的记录。
  10. 点击你的名字,然后选择切换 Switch back to Lightning Experience.

    轻拍自己的背部!您不仅创建了令人惊叹的Lightning组件,还了解了在Visualforce中利用Lightning组件的轻松方式,无论您是在Lightning Experience中还是在Salesforce Classic中使用Visualforce页面。接下来的步骤中,您可能需要编辑页面布局编辑器中的页面布局,以使Visualforce页面的空间更高一些。但是我们会把这个留给你。现在是时候吹嘘一下,去展示你的同事们!

Lightning-应用程序(5)

创建一个类似的属性闪电组件

现在,您已经成功地掌握了Lightning组件的基础知识,现在是时候认真思考并构建一个真正有用的工具。我们将利用我们的知识,并使用Lightning组件替换VisualConfiguration类似的页面,它可以做同样的事情 – 还有更多!当你完成时,你会有一个闪电组件:

  • 根据Salesforce Admin定义的搜索条件检索并显示数据。
  • 使用系统事件导航到记录。
  • 对记录上的CRUD操作使用force:recordData。
  • 公开在App Builder中使用的设计参数。

第1部分 – 创建Apex类控制器

显然,我们的组件将需要来自Salesforce的数据,就像我们用这个组件替换的Visualforce页面一样。但是,Visualforce页面只能用硬编码的条件返回属性。我们的组件将(最终)允许我们的Salesforce Admin通过在组件添加到页面时定义搜索条件来确定要搜索的内容。所以让我们通过创建一个新的Apex类来接受搜索条件。

  1. 在开发人员控制台中,选择 File > New > Apex Class. 命名类MyPropertyController,然后单击确定。
  2. 将默认代码替换为:
    public with sharing class MyPropertyController {
        @AuraEnabled
        public static List<Property__c> getSimilarProperties (Id recordId, String searchCriteria, Decimal beds, Decimal price, Decimal priceRange ) {
             if (searchCriteria == 'Bedrooms') {
                 return [
                     SELECT Id, Name, Beds__c, Baths__c, Price__c, Broker__c, Status__c, Thumbnail__c
                     FROM Property__c WHERE Id != :recordId AND Beds__c = :beds
                 ];
             } else {
                 Decimal range;
                 if (priceRange == null) {
                     range = 100000;
                 } else {
                     range = priceRange;
                 }
                 return [
                     SELECT Id, Name, Beds__c, Baths__c, Price__c, Broker__c, Status__c, Thumbnail__c
                     FROM Property__c WHERE Id != :recordId AND Price__c > :price - range AND Price__c < :price + range
                 ];
             }
         }
    }
    
    您将已经识别出@AuraEnabled和静态签名,以便我们的Lightning组件可以调用getSimilarProperties方法。这个方法有四个参数:recordId,searchCriteria,床位和价格。 recordId将用于当前的Property记录。然后,该方法使用参数根据searchCriteria是否为Bedrooms来选择相似的属性。
  3. 保存文件并关闭其在开发者控制台中的标签。

第2部分 – 创建类似的属性组件

  1. 在开发者控制台中,选择File > New > Lightning Component.
  2. 命名组件SimilarProperties,选择 Lightning Record Page, 然后单击 Submit.
  3. 将d controller="MyPropertyController" 添加到 <aura:component> 标记中。

    就像我们在HelloWorld组件中指定的那样,我们将组件指向我们刚刚创建的Apex类。

  4. 将以下代码粘贴到<aura:component>标签内的新组件中:
    <aura:attribute name="recordId" type="Id" />
    <aura:attribute name="similarProperties" type="Object[]" />
    <aura:attribute name="property" type="Property__c" />
    <aura:attribute name="remoteRecordId" type="Id" />
    <aura:attribute name="showDialog" type="String" default="false" />
    
    <force:recordData aura:id="propertyService"
                      recordId="{!v.recordId}"
                      targetRecord="{!v.property}"
                      recordUpdated="{!c.doInit}"
                      layoutType="FULL" />
    
    <lightning:card iconName="custom:custom85" title="Similar Properties">
        <div class="slds-p-left_medium slds-p-right_medium">
            <ul class="slds-list_vertical slds-has-dividers_top-space">
                <aura:iteration items="{!v.similarProperties}" var="item" indexVar="i">
                    <li class="slds-list__item">                   
                        {!item.Name}
                    </li>
                </aura:iteration>
            </ul>
        </div>
    </lightning:card>
    

    只有几行代码就有很多事情要做。你会注意到的第一件事是三个<aura:attribute>声明。因为我们选择了Lightning Record Page,所以组件还使用force:hasRecordId接口,该接口将自动检索当前Record页面的Id并将其存储在名为recordId的<aura:attribute>中。

    接下来,我们有一个名为similarProperties的属性,用于存储由Apex类返回的属性。这将采取JSON的形式,所以它的类型被设置为Object []。

    Summer 17发布的新功能之前在Developer Preview中名为force:recordPreview现在已经进入Beta版,并已重命名为<force:recordData>。 force:recordData自动检索由其recordId属性指定的记录,然后将该数据存储在由targetRecord属性定义的<aura:attribute>中。然后,force:recordData开始监听页面上其他组件所做更改,当它检测到更改时,它会触发由recordUpdated属性定义的JavaScript函数。

    该组件的UI由另一个名为<lightning:card>的基本闪电组件组成。该卡使用名为custom85的SLDS中的图标。惊喜,这是一个房地产标志!在卡的主体中,您会注意到一个包含列表项<li>的无序列表<ul>。该组件使用<aura:iteration>遍历类似属性属性中的记录,对于每个记录,它显示属性的名称{!item.Name}。

    最后,当组件加载时,它将recordId分配给force:recordData,然后像我们在HelloWorld组件中一样触发doInit函数。所以,我们需要创建这个功能。

  5. 点击开发者控制台右侧栏中的CONTROLLER。
  6. 用以下代码替换默认代码:
    ({
        doInit : function(component, event, helper) {
            var action = component.get("c.getSimilarProperties");
            action.setParams({
                recordId: component.get("v.recordId"),
                beds: component.get("v.property.fields.Beds__c.value"),
                price: component.get("v.property.fields.Price__c.value")
            });
            action.setCallback(this, function(response){
                var similarProperties = response.getReturnValue();
                component.set("v.similarProperties", similarProperties);
            });
            $A.enqueueAction(action);
        }
    })
    
    doInit函数应该看起来很熟悉,因为您已经在HelloWorld组件中看到了很多代码。新的部分是action.setParams部分。这就是我们如何传递参数给被调用的方法,在这种情况下是getSimilarProperties。当<force:recordData>将其记录存储在targetRecord属性中时,它将以ATTRIBUTE_NAME.fields.FIELD_NAME.value的格式存储它。
  7. 保存文件。
  8. 返回到“属性记录”页面,单击“设置Setup icon”图标并选择“编辑页面”。
  9. 找到定制组件下的SimilarProperties组件,并将其拖到右侧列顶部的页面上。
  10. 点击保存,然后点击返回。

    该页面现在应该显示相似的属性(相同价格范围内的属性列表)。

Screenshot of the SimilarProperties Lightning Comopnent.

现在让我们玩一下。

  1. 双击属性记录的价格进行编辑。
  2. 降价约$ 50,000,然后点击保存按钮。
    请注意,组件根据价格变化重新加载。如果你没有得到任何新的物业,再次改变价格。换句话说,force:recordData注意到价格变化并触发了它的recordUpdated函数,它在加载时调用的doInit函数。

第3部分 – 改进用户界面

在构建Lightning组件时,显然我们可以将所有标记放在一个组件中。但是,更好的做法是把事情分解成更小的组件,以包含在较大的组件中。这意味着这些子组件也可以用在其他组件中。

对于这一步,我们将创建一个组件来显示每条记录的更多信息。

  1. 在开发者控制台中,选择 File > New > Lightning Component.
  2. 将该组件命名为SimilarProperty,并取消选中所有复选框。
  3. 将默认标记替换为以下内容:
    <aura:component>
        <aura:attribute name="propertyId" type="Id" />
        <aura:attribute name="targetFields" type="Property__c" />
        <aura:attribute name="showDialog" type="String" />
        <aura:attribute name="remoteRecordId" type="Id" />
    
        <force:recordData aura:id="propertyRecord"
                          recordId="{!v.propertyId}"
                          targetFields="{!v.targetFields}"
                          fields="Name, Beds__c, Baths__c, Price__c, Status__c, Thumbnail__c"
                          />
    
        <div class="slds-media">
            <div class="slds-media__figure">
                <img src="{!v.targetFields.Thumbnail__c}" class="slds-avatar_large slds-avatar_circle" alt="{!v.targetFields.Title_c}" />
            </div>
            <div class="slds-media__body">
                <div class="slds-grid">
                    <a onclick="{!c.navToRecord}">
                        <h3 class="slds-text-heading_small slds-m-bottom_xx-small">{!v.targetFields.Name}</h3>
                    </a>
                    <!-- Edit button goes here -->
                </div>
                <div aura:id="propertyDetails" class="slds-m-top_small">
                    <ul class="slds-grid slds-wrap">
                        <li class="slds-list__item slds-size_1-of-2"><span class="slds-text-color_weak slds-m-right_small">Beds:</span> {!v.targetFields.Beds__c}</li>
                        <li class="slds-list__item slds-size_1-of-2"><span class="slds-text-color_weak slds-m-right_small">Baths:</span> {!v.targetFields.Baths__c}</li>
                        <li class="slds-list__item slds-size_1-of-2"><span class="slds-text-color_weak slds-m-right_small">Price:</span> {!v.targetFields.Price__c}</li>
                        <li class="slds-list__item slds-size_1-of-2"><span class="slds-text-color_weak slds-m-right_small">Status:</span> {!v.targetFields.Status__c}</li>
                    </ul>
                </div>
            </div>
        </div>
    </aura:component>
    
    这个组件有几个<aura:attributes>,但是让我们从<force:recordData>对象开始。这个<force:recordData>看起来和我们主要组件中的一样,但是不是使用layoutType =“FULL”来获取对象的所有字段,现在我们只定义了我们感兴趣的字段字段属性。数据本身存储在targetFields属性中,我们用它来显示<li>元素中的数据。使用targetFields,更容易引用该字段的值。您只需使用格式targetFields.field_name而不是ATTRIBUTE_NAME.fields.FIELD_NAME.value。

    注意这个组件没有init事件处理程序。这是因为记录正在被<force:recordData>对象检索。

  4. 保存文件。
  5. 回到SimilarProperties.cmp组件。将<li>中的{!item.Name}替换为:
    <c:SimilarProperty propertyId="{!item.Id}" remoteRecordId="{!v.remoteRecordId}" showDialog="{!v.showDialog}" />
    
    在另一个组件中嵌入组件时,还可以设置该组件中任何<aura:attribute>的值。在这种情况下,正在设置<force:recordData>对象使用的propertyId,以及稍后将使用的一些属性。
  6. 保存文件。
  7. 返回到“财产记录详细信息”页面并刷新它。

Screenshot of the SimilarProperty Lightning Component revised.

其网格系统是SLDS非常酷的功能之一。看看床,浴场,价格和状态如何很好地排队?这是因为他们正在使用内置到SLDS的网格 – 由具有slds-grid类的任何元素指示。网格包含12列,您只需定义项目的大小和列数。对于这个组件,网格中的每个项目都有一个slds-size_1-of-2的类别,它转化为水平空间的50%。

第4部分 – 导航到一个类似的属性

在SimilarProperty组件中,地址(存储在名称字段中)是一个可点击的链接。 <a>元素有一个触发navToRecord函数的onclick事件。

  1. 在Developer Console中打开SimilarProperty组件。
  2. 点击CONTROLLER并将占位符代码替换为:
    ({
        navToRecord : function (component, event, helper) {
            var navEvt = $A.get("e.force:navigateToSObject");
            navEvt.setParams({
                "recordId": component.get("v.propertyId")
            });
            navEvt.fire();
        }
    })
    
    This is a very straightforward function. It simply declares a variable that instructs the Lightning Framework, that’s the $A, to call the e.force:navigateToSObject event. The Id of the property is passed as a parameter of the event.
  3. 保存文件。
  4. 返回到“属性记录详细信息”页面并刷新它。在“类似属性”组件中,单击属性的名称以导航到该属性记录页面。

第5部分 – 编辑类似的属性“到位”

我们将添加到组件的最后一点功能是允许用户在相似的属性列表中编辑其中一个属性,而无需实际导航到它。

  1. 在开发者控制台中,返回到SimilarProperty组件标记。
  2. 用下面的代码替换 <!-- Edit button goes here -->
    <lightning:buttonIcon iconName="utility:edit" class="slds-col_bump-left" variant="bare" alternativeText="Edit Record" onclick="{!c.editRecord}" />
    
    另一个基本闪电组件<lightning:buttonIcon>允许我们使用一个图标作为按钮。在这种情况下,它将使用SLDS图标实用程序部分的编辑图标,这是一支铅笔。当用户点击按钮时,editRecord函数将会触发。
  3. 保存文件。
  4. 在侧边栏中点击CONTROLLER,然后添加以下功能(再次注意添加一个逗号来分隔功能):
    editRecord : function(component, event, helper) {
        var editRecordEvent = $A.get("e.force:editRecord");
        editRecordEvent.setParams({
            "recordId": component.get("v.propertyId")
        });
        editRecordEvent.fire();
    }
    
  5. 保存文件。
  6. 返回到“财产记录”页面并刷新它。
    Screenshot of editing in place.
  7. 在“类似属性”组件中,单击属性的编辑图标以便就地编辑该属性。

    将编辑保存到记录后,注意它在组件中更新,因为<force:recordData>对象正在监视记录的更改。

第6部分 – 创建一个自定义编辑表单

组件真的开始聚集在一起,但是我们将对用户编辑远程记录时显示的字段进行小小的更改。由于我们只在闪电组件中显示几个字段,因此我们只会在编辑器窗体中显示这些相同的字段。

  1. 在开发者控制台中,创建一个名为SimilarPropertyEdit的新Lightning组件。再次,不要选中所有的框。
  2. 用下列内容替换组件的内容:
    <aura:component>
        <aura:attribute name="showDialog" type="String" default="false" />
        <aura:attribute name="remoteRecordId" type="Id" />
        <aura:attribute name="selectedProperty" type="Property__c" />
        <aura:handler name="change" value="{!v.showDialog}" action="{!c.toggleDialog}" />
        <aura:handler name="change" value="{!v.remoteRecordId}" action="{!c.getRecord}" />
    
        <force:recordData aura:id="editRecord"
                             targetRecord="{!v.selectedProperty}"
                             fields="Id,Name,Beds__c,Baths__c,Price__c,Status__c"
                             mode="EDIT" />
    
        <div aura:id="editDialog" role="dialog" tabindex="-1" aria-labelledby="header43" class="slds-modal">
            <div class="slds-modal__container">
                <div class="slds-modal__header">
                    <button class="slds-button slds-modal__close " title="Close" onclick="{!c.toggleDialog}">
                        <lightning:icon iconName="utility:close" variant="bare" ></lightning:icon>
                        <span class="slds-assistive-text">Close</span>
                    </button>
                    <h2 class="slds-text-heading_medium">Edit Record</h2>
                </div>
                <div class="slds-modal__content slds-p-around_medium slds-grid slds-wrap slds-grid_align-spread">
                    <lightning:input aura:id="propName" name="propName" label="Property Name" required="true" value="{!v.selectedProperty.fields.Name.value}" class="slds-size_1-of-1 slds-p-horizontal_x-small" />
                    <lightning:input aura:id="propBeds" name="propBeds" type="number" label="Beds" value="{!v.selectedProperty.fields.Beds__c.value}" class="slds-size_1-of-2 slds-p-horizontal_x-small" />
                    <lightning:input aura:id="propBaths" name="propBaths" type="number" label="Baths" value="{!v.selectedProperty.fields.Baths__c.value}" class="slds-size_1-of-2 slds-p-horizontal_x-small" />
                    <lightning:input aura:id="propPrice" name="propPrice" type="number" label="Price" value="{!v.selectedProperty.fields.Price__c.value}" class="slds-size_1-of-2 slds-p-horizontal_x-small" />
                    <lightning:input aura:id="propStatus" name="propStatus" label="Status" value="{!v.selectedProperty.fields.Status__c.value}" class="slds-size_1-of-2 slds-p-horizontal_x-small" />
                </div>
                <div class="slds-modal__footer">
                    <button class="slds-button slds-button_neutral" onclick="{!c.toggleDialog}">Cancel</button>
                    <button class="slds-button slds-button_brand" onclick="{!c.saveRecord}">Save</button>
                </div>
            </div>
        </div>
        <div aura:id="overlay" class="slds-backdrop"></div>
    </aura:component>
    
    此组件的标记使用SLDS中的模式。而且,正如您以前所见,<force:recordData>正在检索我们希望能够编辑的字段。但是这个<force:recordData>的实例有两个不同之处。第一个区别是没有定义recordId属性。我们将根据用户选择的记录来动态分配该值。其次,该实例将其模式属性设置为EDIT。这使实例能够更新记录。该组件没有init处理程序,而是使用更改处理程序来监视remoteRecordId属性的更改。

    每个按钮都有一个onclick处理函数,我们需要为其编写函数。

  3. 点击CONTROLLER并将占位符代码替换为:
    ({
        getRecord : function(component) {
            var tempRec = component.find("editRecord");
            tempRec.set("v.recordId", component.get("v.remoteRecordId"));
            tempRec.reloadRecord();
        },
        toggleDialog : function(component, event, helper) {
            helper.showHideModal(component);
        },
        saveRecord : function(component,event,helper) {
            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.selectedProperty.fields.Beds__c.value", propBeds);
            component.set("v.selectedProperty.fields.Baths__c.value", propBaths);
            component.set("v.selectedProperty.fields.Price__c.value", propPrice);
    
            var tempRec = component.find("editRecord");
            tempRec.saveRecord($A.getCallback(function(result){
                console.log(result.state);
                if (result.state === "SUCCESS" || result.state === "DRAFT") {
                    var event = $A.get("e.c:recordUpdated");
                    event.fire();
                } else if (result.state === "ERROR") {
                    console.log('Error: ' + JSON.stringify(result.error));
                } else {
                    console.log('Unknown problem, state: ' + result.state + ', error: ' + JSON.stringify(result.error));
                }
            }));       
            helper.showHideModal(component);
        }
    })
    

    当remoteRecordId改变时,getRecord函数将会触发。它将remoteRecordId的新值动态地分配给<force:recordData>的editRecord实例,这会触发请求字段的检索。

    toggleDialog函数正在调用位于Helper文件中的函数。 Helper文件只是一个JavaScript文件,我们在其中编写我们想要重用的函数。注意saveRecord函数的末尾还有一个对showHideModal函数的调用。在标记<aura:handler name =“change”value =“{!v.showDialog}”action =“{!c.toggleDialog}”/>时,会监视showDialog属性的更改,并在发生此功能时触发。

    saveRecord函数负责保存对该属性的任何更改。它首先将三个<lightning:input>实例中的字符串值用数值转换为整数。然后它更新<force:recordData>实例的targetRecord中的值。然后使用<force:recordData>的saveRecord方法将更改保存回Salesforce。如果保存更改成功,则会触发一个名为recordUpdated的事件,我们将在下一步创建。但首先,我们将showHideModal函数添加到Helper。

  4. 单击HELPER将帮助器文件添加到组件。将占位符代码替换为:
    ({
        showHideModal : function(component) {
            var modal = component.find("editDialog");
            $A.util.toggleClass(modal, 'slds-fade-in-open');
            var overlay = component.find("overlay");
            $A.util.toggleClass(overlay, 'slds-backdrop_open');
            component.set("v.showDialog", "false");
        }
    })
    
    这个简单的函数在SLDS中打开和关闭一个CSS类来显示和/或隐藏模式。
  5. 切换回SimilarProperties组件markup.
  6. 在关闭</ lightning:card>标记之前添加一个新行(可能是第23行):
    <c:SimilarPropertyEdit showDialog="{!v.showDialog}" remoteRecordId="{!v.remoteRecordId}" />
    
    注意我们将使用remoteRecordId属性动态地将recordId分配给组件的<force:recordData>实例。
  7. 切换到SimilarProperty组件的控制器。
  8. 将editRecord函数更新为:
        editRecord : function(component, event, helper) {
        var recId = component.get("v.propertyId");
        component.set("v.remoteRecordId", recId);
        component.set("v.showDialog", "true");
    }
    

    editRecord函数现在简单地将当前记录的Id分配给RemoteRecordId属性,SimilarPropertyEdit组件用来获取其数据。 showDialog属性设置为true,这将导致SimilarPropertyEdit组件中的toggleDialog函数触发,打开自定义窗体。

    最后,我们需要添加一个Lightning事件让页面上的其他组件知道我们已经更新了记录。

  9. 在开发者控制台中,点击 File > New > Lightning Event.
  10. 命名事件 recordUpdated.

    闪电事件触发任何其他组件可以侦听的事件。事实上,我们现在要让这个组件监听这个事件,这样我们可以在页面上有多个组件实例一起更新。

  11. 切换回 SimilarProperties 组件。
  12. 在最后一个<aura:attribute>之后添加一个新行并添加:
    <aura:handler event="c:recordUpdated" action="{!c.doInit}" />
    
    现在,当组件听到recordUpdated事件时,它将触发它的doInit函数。
  13. 保存所有文件,File > Save All.
  14. 重新加载属性页面,然后单击编辑图标查看新的自定义编辑表单。

Screenshot of new edit form with Property Name, Beds, Baths, Price, and Status fields.

第7部分 – 应用微调

你做了一个了不起的工作!但是作为一个用户,当组件第一次加载到页面上时,这是一点点震动。你最初看到的只是卡片的标题栏,然后内容进来。想象一下,如果有网络问题。用户甚至可能不知道他们应该有内容,和/或最新的内容是否已经加载。 Salesforce使用微调器来指示网络活动何时发生。让我们添加一个微调器来指示何时正在检索或刷新数据。

  1. 在Developer Console中,打开主SimilarProperties组件。
  2. 在标记(可能行25)底部的<c:SimilarPropertyEdit …组件上方添加一个新行,并将以下内容添加到新行中:
    <lightning:spinner aura:id="spinner" variant="brand" size="large"/>
    
  3. 保存永远不会结束微调的文件。Screenshot of never ending spinner.

    如果刷新“财产记录”页面,则会发现一些问题。首先,微调整个页面,其次,它永远不会消失!默认情况下,<lightning:spinner>对象覆盖整个页面。但是,我们可以将其限制为只包含SLDS中的类所在的组件。

  4. 将class =“slds-is-relative”添加到<lightning:card>标记,使其看起来像这样:
    <lightning:card iconName="custom:custom85" title="Similar Properties" class="slds-is-relative">
    
  5. 保存文件。
  6. 单击STYLE将自定义CSS文件添加到SimilarProperties组件,并用下列内容替换默认内容:
    .THIS {
        min-height: 153px;
    }
    
    在Lightning组件中使用自定义CSS时,类.THIS将自动应用于包装组件的HTML元素。在这种情况下,这就是<lightning:card>。 min-height属性指定组件的最小高度。我们已经把它设置到一个财产记录的高度。
  7. 保存文件。
  8. 重新载入属性记录页面。

    您可以看到,微调控制器现在只覆盖组件,而作为加载到页面上的组件,在有数据之前,组件比之前更高。现在,我们只在数据加载时显示微调器。

  9. 在开发者控制台中,点击CONTROLLER打开SimilarPropertiesController。
  10. 将控制器代码更新为:
    ({
        doInit : function(component, event, helper) {
            var spinner = component.find("spinner");
            $A.util.removeClass(spinner, "slds-hide");
            var action = component.get("c.getSimilarProperties");
            action.setParams({
                recordId: component.get("v.recordId"),
                beds: component.get("v.property.fields.Beds__c.value"),
                price: component.get("v.property.fields.Price__c.value")
            });
            action.setCallback(this, function(response){
                var similarProperties = response.getReturnValue();
                component.set("v.similarProperties", similarProperties);
                $A.util.addClass(spinner, "slds-hide");
            });
            $A.enqueueAction(action);
        }
    })
    
    您刚刚添加了三行代码到控制器。第一行var spinner = component.find(“spinner”);为微调器创建一个变量引用。 component.find()方法用于查找标记中的元素。当我们创建<lightning:spinner>时,我们为其指定了一个“spinner”的aura:id。所以,我们说,进入标记,找到有光环的东西:微调的身份证。

    $ A.util.removeClass(s​​pinner,“slds-hide”);指示框架(记住$ A?)使用其实用方法removeClass()从微调框中删除slds-hide的CSS类。顾名思义,slds-hide类隐藏了它所放置的任何元素。因此,在slds-hide类被删除的情况下,在组件加载时,微调器将始终可见。在动作的回调中,我们添加了$ A.util.addClass(s​​pinner,“slds-hide”);它只是把slds-hide类加回到微调器上。

  11. 保存文件,然后刷新“属性记录”页面。

    现在,当我们加载数据时,微调器会短暂出现,一旦数据到达,就会消失。

第8部分 – 添加一个图标

当您创建Lightning组件时,您可以选择在Lightning App Builder中为该组件的名称旁边显示的组件创建一个图标。默认情况下,每个自定义组件都会得到一个带有白色闪电的蓝色方形图标。让我们给我们的组件自己的图标。

  1. 在开发者控制台中,点击SVG
  2. 在新的浏览器选项卡中,导航回SLDS站点。
  3. 导航到该网站的图标部分。
  4. 向下滚动以在图标的“自定义”部分中找到custom85。步骤5-13是信息性的只是因为在步骤14我们给你的图标的代码。但是,如果您想使用不同的图标,则需要执行以下步骤。
  5. 通常情况下,您可以单击导航面板中的“下载”链接,然后向下滚动到“图标”部分,然后单击“下载”按钮。
  6. 导航到下载的zip文件并解压后,打开文件夹,然后打开自定义文件夹。
  7. 找到custom85.svg文件并在文本编辑器中打开它。
  8. 复制SVG中的<path>标记。
  9. 在开发者控制台中,切换到SimilarProperties.svg。
  10. 将第二个<path>标签替换为您刚刚复制的标签。
  11. 在刚刚粘贴的<path>开始处,在“d”属性之前添加fill =“#fff”。
  12. 将<svg>标签中的width =“120px”height =“120px”viewBox =“0 0 120 120”更改为:
    width="100px" height="100px" viewBox="0 0 100 100"
    
  13. 将第一个<path>的填充更改为#F26891。
    这是我们承诺的代码!
  14. 选择全部,并使用以下命令替换Dev Console中的.svg文件:
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
        <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
            <path d="M120,108 C120,114.6 114.6,120 108,120 L12,120 C5.4,120 0,114.6 0,108 L0,12 C0,5.4 5.4,0 12,0 L108,0 C114.6,0 120,5.4 120,12 L120,108 L120,108 Z" id="Shape" fill="#2A739E"/>
            <path fill="#FFF" d="m78 24h-50v-2c0-1.1-0.9-2-2-2h-4c-1.1 0-2 0.9-2 2v56c0 1.1 0.9 2 2 2h4c1.1 0 2-0.9 2-2v-46h50c1.1 0 2-0.9 2-2v-4c0-1.1-0.9-2-2-2z m-4 14h-34c-3.3 0-6 2.7-6 6v22c0 3.3 2.7 6 6 6h34c3.3 0 6-2.7 6-6v-22c0-3.3-2.7-6-6-6z m-5.5 17h-2.5v10c0 0.6-0.4 1-1 1h-4c-0.6 0-1-0.4-1-1v-6c0-0.6-0.4-1-1-1h-4c-0.6 0-1 0.4-1 1v6c0 0.6-0.4 1-1 1h-4c-0.6 0-1-0.4-1-1v-10h-2.5c-0.5 0-0.7-0.6-0.3-0.9l11.2-10.9c0.4-0.3 0.9-0.3 1.3 0l11.2 10.9c0.3 0.3 0.1 0.9-0.4 0.9z"></path>
        </g>
    </svg>
    
  15. 保存文件。
  16. 返回到“属性记录”页面,单击“设置”图标Setup icon,然后选择Edit Page.

    向下滚动到App Builder左侧栏中的自定义组件,欣赏你美丽的图标!

Screenshot of custom icon for the SimilarProperties component.

第9部分 – 添加设计参数

最后,我们将通过暴露在将组件添加到页面时可以更改的参数来使Admins爱我们。我们将给他们指定一个搜索条件的选项,以及按价格搜索的范围。我们也将确保你不会无意中将组件添加到不起作用的页面。例如,我们不想将“类似属性”组件添加到“联系人记录”页面。使用Design文件,我们可以指定组件可以使用的对象类型。因此,例如,在“联系人记录”页面上,组件将不会显示在Lightning App Builder的可用组件列表中。

  1. 如果关闭了App Builder,请在“属性记录详细信息”页面上单击“设置”图标Setup icon,然后选择Edit Page.
  2. 移除SimilarProperties组件并保存页面(注意:如果跳过这一步,在将来的步骤中编辑设计文件时会出现错误)。

    为了限制组件可以放置的页面的类型,您必须首先从分配给它的任何布局中移除该组件。

  3. 切换回开发者控制台,在SimilarProperties组件中,在最后一个<aura:attribute>之后添加一行,然后粘贴以下代码:
    <aura:attribute name="searchCriteria" type="String" default="Price" />
    <aura:attribute name="priceRange" type="String" default="100000" />
    
    为了在App Builder中公开参数,我们首先需要在组件本身中添加我们想要公开的<aura:attribute>。
  4. 将<lightning:card>的title属性更改为title =“{!’”+ v.searchCriteria}“的相似属性。它现在应该是这样的:
    <lightning:card iconName="custom:custom85" title="{! 'Similar Properties by ' + v.searchCriteria}" class="slds-is-relative">
    
  5. 保存文件。
  6. 单击CONTROLLER,然后将调用修改为action.setParams(),如下所示,以传递searchCriteria和priceRange属性的值:
    action.setParams({
            recordId: component.get("v.recordId"),
            beds: component.get("v.property.fields.Beds__c.value"),
            price: component.get("v.property.fields.Price__c.value"),
            searchCriteria: component.get("v.searchCriteria"),
            priceRange: parseInt(component.get("v.priceRange"), 10)
        });
    
  7. 保存文件。
  8. 单击设计,用下面的代码替换默认的内容:
    <design:component label="Similar Properties">
        <sfdc:objects>
            <sfdc:object>Property__c</sfdc:object>
        </sfdc:objects>
        <design:attribute name="searchCriteria" label="Search By" datasource="Bedrooms, Price" default="Price" description="Search for similar houses based on what criteria?" />
        <design:attribute name="priceRange" label="Price Range" default="100000" description="When searching by Price, search using the price plus or minus this amount" />   
    </design:component>
    

    设计属性是在App Builder中公开的参数。对于每个设计属性,在组件中必须有与设计属性完全相同名称的对应aura属性。您要公开的设计参数可以是文本输入或选择列表。应该是选择列表的参数包括一个带逗号分隔的选项列表的数据源属性,您可以在<design:attribute name =“searchCriteria”>中看到。我们还为priceRange添加了一个属性。 Apex类将使用此值来搜索加或减这个值的属性。

    <sfdc:objects>列表定义了组件可以在其上使用的对象页面的类型。如果你想在Property__c页面以外的地方使用这个组件,你只需要在列表中添加一个新的<sfdc:object>。

  9. 保存文件。 (注意:如果出现错误,请在App Builder中删除页面上的类似属性组件,然后保存。)
  10. 如果关闭了App Builder,请在“属性记录详细信息”页面上单击“设置”图标Setup icon,然后选择“编辑页面”。
  11. 单击组件列表顶部的刷新图标。

    这将重新加载组件,以便我们获得所做的更改,例如添加设计文件。
    Refresh components, insert Similar Properties Component, modify search criteria.

  12. 在“自定义组件”下,请注意组件的名称现在是“类似属性”(带有空格)。这是设计文件的标签。
  13. 将组件拖回右侧列。请注意,右侧栏目包含搜索条件的设计参数。
  14. 选择价格作为搜索条件,以75000作为价格范围。点击价格范围字段外部,让App Builder知道您已完成编辑字段。

    注意,在您进行更改时,App Builder正在刷新页面上的组件。

  15. 将组件的第二个副本拖放到页面上,并将其放在页面上第一个组件的上方或下方。
  16. 将搜索标准切换到 Bedrooms.
  17. 单击保存,然后返回到“属性记录”页面。
  18. 玩编辑卧室的价格或数量,并注意如何改变反映在组件的两个实例。

    祝贺您成为一名真正的Lightning组件开发人员。我可以说,你创造了一个惊人的组件!

Lightning-应用程序(4)

创建一个“Hello World”闪电组件

现在,您已经学会了如何将Visualforce页面设计为Lightning Experience,您可能会想:“我将继续使用Visualforce来构建和自定义页面”。当然,你可以做到这一点,而且没有任何问题。

但是,由于您已经转向Lightning Experience,因此开始考虑使用Lightning组件构建和自定义页面可能会更好。为什么?因为Lightning组件是Lightning Experience的构建模块,并且它们是模块化的,所以它们可以在多个页面上使用,或者就像我们即将做的那样,同一个组件可以在页面上多次出现,但执行不同的任务!

但为了学习构建闪电组件,你必须从某个地方开始。而且每个开发者都会告诉你,那个地方叫做Hello World。老实说,这是你将要建造的最笨的组件,但它会让你有机会探索构建Lightning组件的基本概念。

到此步骤结束时,您将会:

  • 建立一个简单的闪电组件
  • 学习声明属性并使用数据绑定
  • 从Salesforce中检索数据并将其显示在Lightning组件中。

第1部分 – 创建一个Hello World组件

Lightning组件可以使用开发者控制台来构建,或者当您获得更高级的时候,您可能需要使用Force IDE,Sublime Text,MavensMate或Visual Studio Code。但是由于我们已经在开发者控制台中工作,所以让我们继续前进。

  1. 关闭开发者控制台中的所有打开的选项卡,然后选择 File > New > Lightning Component.
    你会注意到最终的对话框实际上是说新的闪电包,而不是组件。这实际上更准确,因为Lightning组件实际上是一组文件 – 实际上最多八个文件。我们稍后会查看个别文件。
  2. 命名组件: HelloWorld
    接下来我们将选择组件的使用位置。有五个选项,每个选项由对话框中的复选框表示。通过检查一个或多个选项,实际上就是将所谓的接口添加到组件。该接口为组件添加了功能,以便在不同的情况下使用它:

    • Lightning Tab 指定该组件可以用作Salesforce 1中的选项卡。
    • Lightning Page 允许将组件同时放置在主页和记录页面上。
    • Lightning Record Page, 顾名思义,允许组件在“对象记录”页面上使用。
    • Lightning Communities Page 允许组件被使用,是的,你猜对了,一个闪电社区页面。
    • Lightning Quick Action 使组件可以用作Lightning Experience中的快速操作。
  3. 选择 Lightning Record Page 然后单击 Submit.
    恭喜!你已经创建了一个从字面上什么都不做的闪电组件!不过,这也让我们有机会谈论一些事情。比如,为什么当我认为我们正在创建一个闪电组件时,会说<aura:component>? Aura实际上是一个开源的版本框架,我们在上面建立了Lightning框架。

    注意implements =属性。这是组件使用的接口列表。对于这个组件,你勾选了闪电记录页面的框。在代码中,我们使用接口flexipage来表示:availableForRecordHome。在“记录”页面上使用组件时,可能还需要知道正在查看哪个记录。这表示为force:hasRecordId,并且在选择Lightning Record Page时自动添加。

  4. <aura:component> ... </aura:component> 标签内输入Hello。
    如前所述,Lightning组件最多可以包含八个文件。您当前正在使用组件文件或.cmp文件。这是组件的实际HTML标记。其他可能的文件由开发者控制台右侧的按钮表示。

    • Controller—这是一个JavaScript文件,将用于向组件添加功能。
    • Helper— 这也是一个JavaScript文件,用于共享JavaScript功能。
    • Style—这是一个CSS文件,您可以在其中编写自己的CSS组件。
    • Documentation—该文件允许您为组件编写文档,这些文档将显示在组织的帮助页面中。
    • Design—开发者最重要的文件,因为这个文件允许你在App Builder中公开你的组件的参数。
    • SVG—这个可缩放矢量图形是App Builder组件列表中的组件的图标。
  5. 保存文件。

Screenshot of Hello World component showing its eight files.

第2部分 – 将组件添加到页面

构建Lightning组件时,有两种预览组件的方法。首先是将组件添加到闪电应用程序。这实际上是一个独立的应用程序,而不是闪电体验的应用程序。实际上,App Builder本身就是一个Lightning应用程序。另一种方法是简单地把组件放在一个页面上。

  1. 在你的组织中,打开一个财产记录页面,如果你还没有打开。
  2. 点击设置图标Setup icon,然后选择 Edit Page.
  3. 在自定义组件下,找到您的HelloWorld组件并将其拖到右侧列的顶部。
  4. 点击保存,然后点击返回返回到属性页面。

Screenshot of Hello World component in the Property page.

瞧!您已经创建了您的第一个Lightning组件,并将其添加到Lightning Experience中的页面中。但我们不得不承认,这是一个非常愚蠢的组成部分。所以让我们更有趣吧

第3部分 – 使用数据绑定

Salesforce Classic和Lightning Experience之间的区别之一在于,Lightning Experience中的页面全部在客户端呈现。这意味着来自Salesforce的组件和数据作为单独的包到达浏览器,并且必须由Lightning Framework连接在一起。

  1. 在开发者控制台中,将Hello文本替换为:
    <aura:attribute name="greeting" type="String" default="World" />
    
    Hello, {!v.greeting}!
    

    您刚添加了一个名为<aura:attribute>的组件。一个<aura:attribute>基本上是一个存储数据的地方,以便组件可以使用这些数据。每个<aura:attribute>都有一个名称,您将在JavaScript中使用该名称来检索数据。另外这些<aura:attributes>是强类型的。这个属性被声明为String类型,所以如果我们尝试给它赋一个数值,我们会得到一个错误。而且我们已经为该属性分配了一个默认值“World”。

    Lightning组件中的表达式与Visualforce中的表达式几乎相同。他们都使用{! }作为表示表示的符号。唯一的区别是,在Lightning组件中,表达式可能需要评估包中不同文件中的某些内容。因此,Lightning组件使用v。来表示应在视图中评估表达式,这是在组件标记或.cmp文件中表达的一种奇特方式。

    因此,在这个例子中,组件被要求查找位于同一个文件中的问候语的值。

  2. 保存组件并重新加载“属性记录”页面。
    Screenshot of Hello World component.
  3. 回到开发者控制台,在HelloWorld.cmp中,在<aura:attribute />标签下的新行中添加以下输入字段:
    <lightning:input name="Greeting" label="Greeting" value="{!v.greeting}"/>
    

    在Visualforce中,我们使用了由服务器变成HTML的声明标签。在Lightning组件中,我们也有创建一些元素的声明方式。这些被称为基本闪电组件。在这里,您添加了一个<lightning:input>,当组件在页面上呈现时,它将被转换成合适的SLDS标记。

    注意,输入的名字是“Greeting”,也就是<aura:attribute>的名字。这是一件令人难以置信的事情,但我们要让你这样做来说明一个观点。而这一点,“问候”和“问候”是不一样的。在闪电组件世界里,事情是区分大小写的。

    最后,请注意输入值为{!v.greeting}。换句话说,当组件在页面上呈现时,<aura:attribute>的默认值将被预填充到输入中。这被称为数据绑定。

  4. 保存文件并重新加载“属性记录详细信息”页面。
  5. 在输入字段中输入名称以查看数据绑定的实际操作。
    Screenshot of Hello World component showing data binding.
    当您输入输入内容时,无论您输入什么内容,都会立即指定为名为“greeting”的<aura:属性>的{!v.greeting}的值。当这个值改变时,Hello,{!v.greeting}中表达式的值也会改变。

第4部分 – 从Salesforce中提取数据

当然,输入一个输入并改变页面上的一些文本是很有趣的,但是在现实世界中可能不那么有用。大多数(如果不是所有的)Lightning组件都将显示和处理来自Salesforce的数据。他们的工作方式与您在Visualforce中的完全相同。也就是说,他们使用Apex类作为控制器。

对于我们的最后一招,让我们有闪电组件向你问好。换句话说,让我们让组件找出谁登录并显示他们的名字。

  1. 在开发人员控制台中,选择 File > New > Apex Class. 将控制器HelloWorld Controller命名并单击OK。
  2. 添加 with sharing 到类的定义。
    public with sharing class HelloWorldController {
    
        }
    

    带有共享with sharing注释告诉Apex类强制登录用户的字段访问。

  3. Add the following method inside the class:
    @AuraEnabled
    public static User getCurrentUser() {
        return [SELECT Id, FirstName, LastName FROM User WHERE Id = :UserInfo.getUserId() LIMIT 1];
    }
    
    第一个是@AuraEnabled,这个签名指示类允许从闪电组件调用这个方法,第二个是静态的在方法上签名。所有从闪电组件调用的方法必须有这个签名。
  4. 回到 HelloWorld 组件并将 controller="HelloWorldController" 添加到 <aura:component> 标记中。

    就像在Visualforce中一样,我们需要告诉组件将使用哪个Apex Class作为它的服务器端控制器。

  5. 在greeting属性声明之后添加一个init事件处理程序。
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    

    闪电组件使用..<aura:handler> 侦听和响应事件这个处理器的名字是初始化,这也是它当一个组件加载触发事件的名称,但它在网页上呈现前在这种情况下,它是一个名为doInit的函数,它可以在组件包的客户端JavaScript控制器文件中找到。

  6. 点击右侧边栏中的CONTROLLER为该组件创建客户端控制器文件。
  7. 将生成的代码替换为:
    ({
        doInit : function(component, event, helper) {
            var action = component.get("c.getCurrentUser");
            action.setCallback(this, function(response) {
                var user = response.getReturnValue();
                component.set("v.greeting", user.FirstName);
            })
            $A.enqueueAction(action);
        }
    })
    
    如果你做任何JavaScript编码,我们宣布了doInit功能可能看起来有点怪异的方式。这是因为这实际上是一个JSON文件。JSON文件是包含名称/值对的文件。这个名字是doInit和值(用冒号分隔)是函数本身。

    “组件”是将组件的标记传递给函数“查找”诸如<aura:attributes>之类的东西以及实际它的元素值component.get(“c.getCurrentUser”)告诉组件找出它的服务器端控制器,然后getCurrentUser只要记住.cmp文件中的c表示“客户端JavaScript控制器”,而c。客户端JavaScript控制器中的意思是“服务器 – Apex班“。

    所以我们还没有回答如何回复请求,所以我们定义了一个回叫。这个值又分配给<aura:attribute name =“greeting”>这个值在回调函数中,一个变量user,被定义并分配了实际的数据。在组件中。

    最后,$ A.enqueueAction(action);将行动添加到Lightning Framework为构建页面而做的事情队列中。

  8. 保存所有文件,然后刷新属性页面。

    就像魔术一样,你的组件现在知道你已经登录了,并且向你问好!
    使用来自登录用户的数据的Hello World组件的屏幕截图。
    Screenshot of Hello World component using data fromlogged in user.

Lightning-应用程序(3)

使用Visualforce页面作为闪电页面中的组件

在之前的步骤中,我们学习了如何设计一个Visualforce页面以适应Lightning Experience。一旦你意识到一个Visualforce的页面可以成为Lightning Experience的头等公民,它将开启所有新的可能性。实际上,Visualforce页面不仅可以用作Lightning Experience中的完整页面或选项卡,就像在上一步中一样,Visualforce页面也可以用作Lightning Experience页面中的组件。

在这一步你会:

  • 使用App Builder修改Lightning页面。
  • 在“Lightning Experience”页面中启用Visualforce页面作为组件。

第1部分 – 使Visualforce页面可用于闪电体验

  1. 在您的组织中,单击“属性”并选择任何属性以查看“属性记录”页面。
    这是Property对象的标准Record页面。但是,如果您向下滚动该属性的图片,则会看到一些奇怪的情况。它看起来像一个Visualforce页面…但在闪电页面!而这正是它是什么。
    Screenshot showing look and feel of related properties
  2. 点击设置图标Setup icon,然后选择Click  and select Edit Page.
  3. 单击以选择App Builder中页面顶部的“突出显示”面板(A)。
    Screenshot of the Lightning App Builder

    点击Hightlights面板激活App Builder(B)右侧栏中的几个选项。

  4. 在“分配页面布局Assign Page Layouts”部分中,单击“属性布局Property Layout”(C)。

    当然,你可以通过点击Setup图标,选择Setup,点击Object Manager选项卡,滚动到所需的Object,在我们的例子Property中,然后点击选择它,点击左侧的Page Layouts链接手列并点击所需的布局。这取决于你选择哪一个更容易。

  5. 在“页面布局编辑器”中向下滚动,并注意已添加名为“类似属性”的部分。该部分内部是一个Visualforce页面,也被称为 Similar Properties.
  6. 单击主页Home 选项卡并在快速查找框中输入Visualforce并选择Visualforce页面。
  7. 点击类似属性页面的编辑。
  8. 选择 Available for Salesforce mobile apps and Lightning Pages.
    这个神奇的小复选框告诉Lightning Experience,您希望将此Visualforce页面不仅用作页面或选项卡,而且还希望能够将其用作组件,就像您在App Builder中使用的其他标准和自定义组件一样并自定义页面。
  9. 单击保存并关闭浏览器中的设置选项卡。

第2部分 – 再次修改标记!

一旦启用了用于Salesforce 1和Lightning Experience的Visualforce页面,使用App Builder将其添加到页面中很容易。但首先,因为我们已经看到该页面看起来像Salesforce Classic,所以让我们像上一个练习一样更新Lightning Experience的标记。

  1. 在开发者控制台中,选择 File > Open Resource.
  2. 打开 Similar_Properties.vfp.
  3. 将lightningStylesheets =“true”添加到<apex:page>标记。
  4. 保存页面。
  5. 切换回Lightning App Builder,点击Back返回到Property Record页面。
  6. 向下滚动到“类似属性”VF页面,查看对嵌入式Visualforce页面的更改。

Screenshot showing revised look and feel of related properties

第3部分 – 使用Visualforce页面作为闪电组件

页面定制是Lightning Experience的主要功能之一,因此,现在让我们根据您的Visualforce专业知识,在Salesforce Classic中做一些难以或甚至不可能的事情。我们将在“属性”页面的右侧列的顶部显示选定属性的类似属性。

  1. 点击Setup icon 然后选择 Edit Page.
  2. 在标准组件列表中找到Visualforce组件。
  3. 将组件拖动到页面上,并将其放在右侧列的顶部。
  4. 在组件属性中,应该自动选择SimilarProperties作为Visualforce页面名称。
    如果您为Salesforce 1和Lightning页面启用了多个Visualforce页面(请记住复选框?),它们将显示在选择列表中,然后选择要显示的页面。
  5. Label 字段中, 输入Other Properties. 将高度设置为 200.
  6. 点击 Save.

    由于这是我们第一次修改标准的属性页面,我们需要激活更新的页面,以便我们的用户可以看到我们已经做了什么。

  7. 点击 Activate.
  8. 点击 App Default ,然后Assign as App Default.
  9. 选择 Dreamhouse Lightning 应用程序,然后单击Next ,然后Save.
  10. 点击 Back 返回属性页面Screenshot showing new Visualforce component on the Properties page

Lightning-应用程序(2)

为用户界面有条件地呈现Visualforce页面

在上一步中,我们让服务器从Visualforce更新标准样式表。虽然页面看起来不错,但只要做一点工作,就可以更接近Lightning Experience的外观。所以这个练习我们将会:

  • 确定用户正在使用的UX环境(Salesforce Classic或Lightning Experience)
  • 将条件呈现逻辑添加到页面以提供来自SLDS的其他样式
  • 使用SLDS中的其他类来调整页面元素

第1部分 – 将用户主题的检查添加到Apex控制器

当用户在Salesforce中请求页面时,系统可以识别用户是处于Salesforce Classic还是Lightning Experience。有了这些知识,我们可以包含或排除页面的区域,以确保用户的正确体验。

  1. 在开发人员控制台中,单击 File > Open > Classes 然后选择DreamhouseProspects Apex 类,然后单击 Open.
  2. 在public String sortOrder {set; get;} 行,添加下面的方法来检测用户的当前主题:
    public Boolean getIsClassic() {
        return (UserInfo.getUiThemeDisplayed() == 'Theme3');
    }
    
    如果用户处于Salesforce Classic中,此方法将返回true,如果用户处于Lightning Experience中,则返回false。
  3. Apex类现在应该是这样的:
    public with sharing class DreamhouseProspects {
        public String sortOrder {set; get;}
    
        public Boolean getIsClassic() {
            return (UserInfo.getUiThemeDisplayed() == 'Theme3');
        }
    
        public List<Lead> getLeads() {
            if (sortOrder == null) {
                sortOrder = 'LastName';
            }        
            return Database.query('SELECT Description,Email,FirstName,Id,LastName,Phone FROM Lead WHERE Company=\'Dreamhouse\' ORDER BY '+sortOrder);
        }
    
        public pageReference sortList() {
            getLeads();
            return null;
        }
    }
    
  4. 保存Apex类并关闭其在开发者控制台中的标签。

第2部分 – 根据用户的主题添加动态块

  1. 在开发者控制台中,通过在打开的<apex:page>标记之后添加一个新行,将指令添加到DreamHouseLeads.vfp页面:
    <apex:slds />
    

    这个简单的标签告诉页面包含Salesforce Lightning设计系统中的CSS,以便我们可以将SLDS中的样式应用于各个页面元素,或者使用SLDS中的标记。以前,您需要创建此CSS的自定义版本,并将其作为静态资源包含在您的组织中。但是这有一个缺点,就是真正的静态 – 所以如果SLDS团队对CSS进行了更改,那么您的静态资源就不会收到这些更改。采用这种新方法,您总能从SLDS接收最新,最好的CSS。

    请记住,lightningStylesheets =“true”不会将SLDS样式表添加到页面,而是将标准样式表从Visualforce更改为像SLDS一样的“外观”。

  2. rendered="{! !isClassic}" 添加到 <apex:slds /> 标签中:
    <apex:slds rendered="{! !isClassic}" />
    
    该页面现在将检查由我们创建的Apex方法返回的值,以检查用户的环境。换句话说,{!isClassic}将评估为true或false。在isClassic前加上感叹号是说“不”的程序化方式。如果用户处于经典模式,则表达式呈现=“{!!isClassic}”,将导致<apex:slds rendered =“false”>,但是<apex:slds rendered =“true”> 。

    因此,如果用户在Lightning中,则可以使用来自SLDS的样式和标记,而在Classic中,该页面仍然像以前一样。

第3部分 – 添加SLDS标题

页面的自动样式看起来相当不错,但页面标题与Lightning Experience中的其他页面不完全相同。请注意,它缺少标题旁边的标准图标,选择列表看起来像标准浏览器选择。此外,选择和排序按钮太靠近表格。如果没关系,那就巧妙地移动。为了这个项目的目的,让我们继续前进,使之与Lightning Experience完全匹配。

  1. 交换<apex:sectionHeader>和<apex:form>元素(在第4行和第5行左右)。

    为了有条件地传递页面的元素,我们需要能够用<apex:outputPanel>标签包装完整的元素。所以,我们刚刚在窗体中移动了节标题,以便我们可以用New按钮,选择列表和排序按钮将它们包装在一起。

  2. 使用<apex:outputPanel rendered =“{!isClassic}”> … </ apex:outputPanel>将整个代码从<apex:sectionHeader>包装到<apex:commandButton>(从第5-14行开始)。你的代码现在应该是这样的:
    <apex:page controller="DreamhouseProspects" lightningStylesheets="true">
        <apex:slds rendered="{! !isClassic}" />
        <apex:pageBlock >
            <apex:form >
                <apex:outputPanel rendered="{!isClassic}">
                    <apex:sectionHeader title="Leads" subtitle="Home"/>
                    <div style="text-align:center;">
                        <apex:commandButton action="{!URLFOR($Action.Lead.New)}" value="New"/>
                    </div>
                    <apex:outputLabel value="Sort: " for="sortList" />
                    <apex:selectList value="{! sortOrder}" size="1" id="sortList">
                        <apex:selectOption itemvalue="LastName" />
                        <apex:selectOption itemvalue="FirstName" />
                    </apex:selectList>
                    <apex:commandButton value="Sort Table" action="{!sortList}" reRender="leads_list"/>
                </apex:outputPanel>
                <apex:pageBlockTable value="{! leads }" var="ct" id="leads_list">
                    <apex:column headerValue="First Name">
                        <apex:outputLink value="/{! ct.Id}">{! ct.FirstName }</apex:outputLink>
                    </apex:column>
                    <apex:column value="{! ct.LastName }"/>
                    <apex:column value="{! ct.Email }"/>
                    <apex:column value="{! ct.Phone }"/>
                </apex:pageBlockTable>              
            </apex:form>
        </apex:pageBlock>
    </apex:page>
    
  3. 保存页面并重新加载到浏览器中。
    Leads list in Lightning Edition with no header

    您已经丢失了整个页面标题和按钮,因为现在只会在{!isClassic}解析为true时才呈现。所以,现在我们可以添加一个匹配Lightning Experience的页面标题。

    虽然我们完全可以创建自己的HTML标记和CSS,但Visualforce开发人员可以做的更多,我们的目标是确保页面看起来与Lightning Experience完全一样。这正是Salesforce UX团队创建SLDS的原因。我们可以简单地将标记从SLDS复制并粘贴到我们的页面中,并修改其占位符内容以显示我们所需的内容。

  4. 导航到SLDS站点。点击侧边栏中的组件,然后点击页面标题,熟悉标记和样式。

    您看到的每个组件的预览都是由您在预览下方看到的标记构建的。这是您可以简单地复制/粘贴,然后修改的标记。

    但是,请注意,对于每个组件(在本例中为页眉),页面的右侧都有变体和状态。这些是所选组件的不同版本。当您选择变体或状态时,示例标记会更改。所以请确保您正在复制所需的变体或状态。

    为了让你更容易,我们已经复制了Object Home变体,并对其进行了修改。

  5. 返回到开发者控制台,在最后一步添加的</ apex:outputPanel>(可能是第16行)之后的新行中添加以下代码:
    <apex:outputPanel rendered="{! !isClassic}">
        <div class="slds-page-header">
            <div class="slds-grid">
                <div class="slds-col slds-has-flexi-truncate" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
                    <div class="slds-media slds-no-space slds-grow">
                        <div class="slds-media__figure">
                            <svg class="slds-icon slds-icon-standard-user .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">
                            <p class="slds-text-title_caps slds-line-height_reset">Lead</p>
                            <h1 class="slds-page-header__title slds-m-right_small slds-align-middle slds-truncate"
                                title="this should match the Record Title">Home</h1>
                        </div>
                    </div>
                    <div class="slds-grid slds-grid_vertical-align-end slds-m-vertical_small">
                        <div class="slds-size_1-of-6 ">
                            <apex:outputLabel value="Sort: " for="sortListLightning" styleClass="slds-form-element__label" />
                            <div class="slds-select_container">
                                <apex:selectList value="{! sortOrder}" size="1" id="sortListLightning" styleClass="slds-select">
                                    <apex:selectOption itemvalue="LastName" />
                                    <apex:selectOption itemvalue="FirstName" />
                                </apex:selectList>
                            </div>
                        </div>
                        <div class="slds-no-flex slds-m-left_x-large">
                            <apex:commandButton value="Sort" action="{!sortList}" reRender="leads_list" styleClass="slds-button slds-button_neutral"/>
                        </div>
                    </div>
                </div>
                <div class="slds-col slds-no-flex slds-grid slds-align-top">
                    <apex:commandButton action="{!URLFOR($Action.Lead.New)}" value="New" styleClass="slds-button slds-button_neutral"/>
                </div>
            </div>
        </div>
    </apex:outputPanel>
    

    当isClassic的值为false时,这个<apex:outputPanel>再次呈现,即用户在Lightning Experience中。

    请注意,页面标题正在使用来自SLDS的SVG格式的图标。即使你没有上传静态资源,因为你包含了<apex:slds>标签,页面知道在哪里可以找到图标。

    您还可以看到我们已经在<apex:outputLabel>和<apex:selectList>周围添加了一些<div>包装,以便它们的标记与SLDS中的标记相匹配,正确的级联将允许它们正确呈现。

  6. 保存文件并在Lightning Experience中重新加载页面以查看您的更改。
    Leads list in Lightning Edition with a new header
    现在,你不得不承认这很酷,对吗?通过对页面进行一些更改,我们现在可以在Lightning Experience中正确呈现标准Visualforce页面,同时在Salesforce Classic中保持其原始外观。

    以防万一你的页面倒下,并轰然倒地…这是代码应该看起来的样子:

    <apex:page controller="DreamhouseProspects" lightningStylesheets="true">
        <apex:slds rendered="{! !isClassic}"/>
        <apex:pageBlock >
            <apex:form >
                <apex:outputPanel rendered="{! isClassic}">
                    <apex:sectionHeader title="Leads" subtitle="Home"/>
                    <div style="text-align:center;">
                        <apex:commandButton action="{!URLFOR($Action.Lead.New)}" value="New"/>
                    </div>
                    <apex:outputLabel value="Sort: " for="sortList" />
                    <apex:selectList value="{! sortOrder}" size="1" id="sortList">
                        <apex:selectOption itemvalue="LastName" />
                        <apex:selectOption itemvalue="FirstName" />
                    </apex:selectList>
                    <apex:commandButton value="Sort Table" action="{!sortList}" reRender="leads_list"/>
                </apex:outputPanel>
                <apex:outputPanel rendered="{! !isClassic}">
                    <div class="slds-page-header">
                        <div class="slds-grid">
                            <div class="slds-col slds-has-flexi-truncate" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
                                <div class="slds-media slds-no-space slds-grow">
                                    <div class="slds-media__figure">
                                        <svg class="slds-icon slds-icon-standard-user .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">
                                        <p class="slds-text-title_caps slds-line-height_reset">Lead</p>
                                        <h1 class="slds-page-header__title slds-m-right_small slds-align-middle slds-truncate"
                                            title="this should match the Record Title">Home</h1>
                                    </div>
                                </div>
                                <div class="slds-grid slds-grid_vertical-align-end slds-m-vertical_small">
                                    <div class="slds-size_1-of-6 ">
                                        <apex:outputLabel value="Sort: " for="sortListLightning" styleClass="slds-form-element__label" />
                                        <div class="slds-select_container">
                                            <apex:selectList value="{! sortOrder}" size="1" id="sortListLightning" styleClass="slds-select">
                                                <apex:selectOption itemvalue="LastName" />
                                                <apex:selectOption itemvalue="FirstName" />
                                            </apex:selectList>
                                        </div>
                                    </div>
                                    <div class="slds-no-flex slds-m-left_x-small">
                                        <apex:commandButton value="Sort" action="{!sortList}" reRender="leads_list" styleClass="slds-button slds-button_neutral"/>
                                    </div>
                                </div>
                            </div>
                            <div class="slds-col slds-no-flex slds-grid slds-align-top">
                                <apex:commandButton action="{!URLFOR($Action.Lead.New)}" value="New" styleClass="slds-button slds-button_neutral"/>
                            </div>
                        </div>
                    </div>
                </apex:outputPanel>
                <apex:pageBlockTable value="{! leads }" var="ct" id="leads_list">
                    <apex:column headerValue="First Name">
                        <apex:outputLink value="/{! ct.Id}">{! ct.FirstName }</apex:outputLink>
                    </apex:column>
                    <apex:column value="{! ct.LastName }"/>
                    <apex:column value="{! ct.Email }"/>
                    <apex:column value="{! ct.Phone }"/>
                </apex:pageBlockTable>              
            </apex:form>
        </apex:pageBlock>
    </apex:page>