• 【Salesforce】Lightning 组件基础知识


    Lightning框架简介

    Lightning框架是Salesforce提供的一套基于用户界面的开发框架,对于开发单页面应用(Single Page Application)有很大的帮助。它和Visualforce可以共存,但开发的方法并不相同。

    Lightning有单独的前端架构,基于名叫aura的框架,主要包括:

    • 组件:由XML语言开发的用户界面,组件内部可以包含其他组件和标准的HTML元素,Lightning框架本身也提供了若干标准组件
    • 应用:Lightning应用是一种特殊的组件,它是整个程序的入口。一个Lightning应用包含若干Lightning组件

    每个组件或应用还包含了:

    • 前端控制器:包含了JavaScript函数,用于和组件的元素互动
    • 辅助函数:可以看作是前端控制器的扩展,用于保存JavaScript辅助函数
    • CSS:保存了针对于某个组件的CSS

    Lightning框架中通过前端控制器和后端进行数据通信,在前端控制器中提供了直接调用Apex代码(后端控制器)的功能。

    Lightning组件

    本文通过一个简单的“Hello World”例子介绍如何建立和编辑Lightning组件、应用,以及组件间的通信。

    新建Lightning组件

    在Developer Console中,点击“File”菜单,指向“New”,点击“Lightning Component”,输入名字“helloworld”,点击“Submit”按钮,即可新建一个Lightning组件。

    新建Lightning组件

    每个Lightning组件不光包含了组件本身,还包含了其他的文件。当新建“helloworld”组件后,在Developer Console的右侧有一个列表,其中包含了和组件相关的各种文件,比如控制器、辅助函数、页面样式、文档等。点击任意一项,即可新建相应的文件。

    定义Lightning组件外观的文件名以“.cmp”结尾,这里就是“helloworld.cmp”。

    Lightning组件相关列表

    在编辑区域中,系统已经默认生成了一段代码:

    <aura:component >
    </aura:component>
    

    每一个Lightning组件都是包含在“aura:component”标签中。

    在“aura:component”标签中写入一段HTML代码:

    <aura:component >
        <p> Hello world! </p>
    </aura:component>
    

    当组件运行之后,在屏幕中就会输出文字。

    新建Lightning应用

    Lightning组件无法单独运行,它必须被包含在一个Lightning应用中。用户只有通过Lightning应用才能运行组件的功能。

    Lightning应用可以看作是一种特殊的组件。在Developer Console中,点击“File”菜单,指向“New”,点击“Lightning Application”,输入名字“helloworld_APP”,点击“Submit”按钮,即可新建一个Lightning应用。

    Lightning组件可以包含其他组件,Lightning应用可以包含组件,但是Lightning应用不能包含应用。

    定义Lightning应用外观的文件名以“.app”结尾,这里就是“helloworld_APP.app”。

    在新建的Lightning应用中,系统也生成了默认的代码:

    <aura:application >
    </aura:application>
    

    每一个Lightning应用都是包含在“aura:application”标签中。

    在应用中调用刚才建立的组件:

    <aura:application >
        <c:helloworld />
    </aura:application>
    

    在窗口右侧的列表上方有“Preview”按钮,点击即可运行Lightning应用。

    预览Lightning应用

    运行Lightning应用,即可看到屏幕上显示了“Hello world!”的字样,说明运行成功了,组件的内容也显示在了应用中。

    为组件增加CSS样式

    在“helloworld”组件中,会显示默认的“Hello world!”文字。如果想修改页面中的显示,可以在Developer Console右侧列表中点击“STYLE”,系统会自动建立“helloworld.css”文件。开发者可以在此文件中修改CSS样式。

    要注意的是,不同于普通的CSS文件,在整个文件中,每一个样式必须带有“.THIS”,它的作用是保证新建的样式只对当前的组件有效。

    向“helloworld.css”文件中添加一段CSS代码:

    p.THIS {
        font-size: 48px;
        color: blue;
    }
    

    保存后再次运行应用,可以看到显示的文字样式已经变化了。

    Lightning组件的CSS更改效果

    为组件添加属性

    现在的“helloworld”组件只能显示一段静态文字。如果需要增加其他动态功能,比如自定义显示文字的内容,则必须要用到组件的“属性”。

    每个组件可以包含若干“属性”。组件的属性可以看作是包含在组件内的变量,它们可以是任何类型。当组件载入后,组件的属性值会被初始化,组件的控制器也可以更改属性的值。组件的属性可以被绑定在组件内部的元素中,从而实现动态功能。

    组件的属性要定义在“aura:attribute”标签中。在组件的元素中,如果想绑定某个属性,需要用“{!v.属性名}”的语法来实现。

    比如在“helloworld”组件中增加一个“message”属性,并输出到“p”标签中:

    <aura:component >
        <aura:attribute name="message" type="String" default="test user" />
    	<p> Hello world! - {!v.message} </p>
    </aura:component>
    

    再次运行Lightning应用,可以看到显示的文字从“Hello world!”变为了“Hello world! - test user”。

    由于属性和组件的元素相互绑定,如果在应用运行时更改属性“message”的值,那么显示的文字也会相应的发生变化。

    数据提供者

    在组件中,如果想绑定一个属性,需要用“{!v.属性名}”的语法。其中的“v”被称为数据提供者(Value Provider)。如果想在组件中显示稍微复杂的表达式而非单独的属性值,同样可以用“{! }”表达式。

    比如在Lightning框架中提供了一个标准显示文字的组件“ui:outputText”,设置其“value”属性即可显示相应的文字。在“helloworld”中可以将代码变为:

    <aura:component >
        <aura:attribute name="message" type="String" default="test user" />
        <p> <ui:outputText value="{! 'Hello world! - ' + v.message}" /> </p>
    </aura:component>
    

    运行应用后输出的文字和之前一样。在这段代码中,“{! }”表达式的里面不光只有属性“message”,还在其之前增加了固定的字符串。

    属性的类型

    属性可以是任何类型,除了基本的字符串、数字等,还可以是集合类型、sObject对象类型。

    比如:

    <!--使用标准sObject对象作为属性类型-->
    <aura:attribute name="account" type="Account" />
    <!--使用标准sObject对象作为属性类型,并初始化某些属性-->
    <aura:attribute name="account" 
                    type="Account" 
                    default="{ 'Name': 'Salesforce',
                                'Type': 'Prospect'}"/>
    <!--使用自定义sObject对象作为属性类型-->
    <aura:attribute name="address" type="Address__c" />
    <!--使用自定义sObject对象作为属性类型,并初始化某些属性-->
    <aura:attribute name="address" 
                    type="Address__c" 
                    default="{ 'Name': 'ExampleAddress',
                                'Street_name__c': 'Example Street Name'}"/>
    <!--使用列表作为属性类型-->
    <aura:attribute name="contactList" type="List" />
    <!--使用列表作为属性类型,并初始化列表-->
    <aura:attribute name="textList" 
                    type="List" 
                    default="['text 1',
                                'text 2',
                                'text 3']" />
    
    <!--在组件中使用sObject对象的字段-->
    <aura:outputText value="{!v.account.Name}" />
    

    循环读取集合类型属性的值

    当一个属性是集合类型时,比如字符串的列表,在组件中可以使用标准组件“aura:iteration”遍历其每一个元素。

    比如:

    <aura:attribute name="textList" 
                    type="List" 
                    default="['text 1',
                                'text 2',
                                'text 3']" />
    
    <!--在组件循环显示字符串-->
    <aura:iteration items="{! v.textList }" var="singleText">
        <p> {! singleText } </p>
    </aura:iteration>
    

    在上面的代码中,使用了标准元素“aura:iteration”。我们将字符串列表属性“textList”绑定到循环列表属性“items”中,并定义“singleText”为每一个循环中列表中变量的名字,类似于“for(String singleText : textList)”。在循环组件的内部,使用“{! }”表达式显示每一个循环元素的内容,注意这里不需要使用“v”了。

    为组件添加功能

    假设在“helloworld”中,需要增加一个按钮,点击之后属性“message”要发生变化。

    用标准组件“ui:button”可以添加按钮,要想实现点击按钮之后更改属性的功能,就必须使用前端控制器。

    在Developer Console的右侧列表中,点击“CONTROLLER”,系统会自动建立一个前端控制器文件“helloworldController.js”。它是一个JavaScript文件,开发者可以在其中添加JS函数实现功能。

    在Developer Console的右侧列表中,点击“HELPER”,系统会自动建立一个辅助函数文件“helloworldHelper.js”。它是一个JavaScript文件,开发者可以在其中添加JS函数,这些函数可以从控制器文件中调用。

    另外要注意的是,在控制器文件中,如果定义了若干函数,它们之间不能互相调用。所以必须将某些公共的功能挪到辅助函数文件中,再使用“helper.函数名”来调用功能。

    在控制器文件中增加一个“handleClick”函数,更改组件中“message”属性的值:

    handleClick : function(component, event, helper) {
        component.set('v.message', 'Updated Message!');
    }
    

    在组件的外观中增加一个按钮,点击之后执行“handleClick”函数:

    <ui:button label="Change text" press="{!c.handleClick}"/>
    

    其中“label”是要在按钮上显示的文字,“press”是一个事件,当点击按钮后,调用“press”里定义的函数。

    注意,这里使用了“{!c.函数名}”的方式来调用JS控制器中的函数,其中的“c”便是代表了“Controller”。

    运行应用,当点击了按钮之后,屏幕上显示的文字便从“Hello world! - test user”变成了“Hello world! - Updated Message!”。

    控制器函数详解

    每一个控制器的函数都默认带有三个参数:

    • component:代表了当前的组件
    • event:代表了触发的事件
    • helper:代表了辅助函数的文件,如果建立了“HELPER”文件,并定义了某些函数,则使用“helper.函数名()”的语法即可调用“HELPER”文件中的函数

    用“component.set('v.属性名', 要设置的值)”的方式可以直接设置组件中属性的值,这是最常用的一种设置方法。

    同样的,也可以用“component.get('v.属性名')”来得到组件中属性的值。

    比如:

    exampleFunction : function(component, event, helper) {
        // 得到message属性的值
        var messageValue = component.get('v.message');
    
        // 设置message属性的值
        component.set('v.message', 'value to set');
    
        // 调用helper文件中的某函数
        var resultFromHelper = helper.exampleHelperFunction();
    }
    

    如果想得到触发某函数的组件元素的内容,则需要使用event参数。

    比如在组件中有一个按钮,点击会触发控制器中的“handleClick()”函数。在“handleClick()”函数中,使用“event.getSource()”即可得到按钮元素。

    组件中的设置:

    <ui:button label="button text" press="{!c.handleClick}" />
    

    控制器中:

    handleClick : function(component, event, helper) {
        // 得到组件中的按钮元素
        var buttonClicked = event.getSource();
    
        // 得到组件中按钮元素的“label”属性
        var buttonValue = buttonClicked.get('v.label');
        // buttonValue的值是“button text”
    }
    

    使用这种方式,可以直接得到组件中元素的各种属性等。

    组件和Apex通信

    在“helloworld”组件中,如果想要通过点击按钮,从数据库中读取一个名叫“GenePoint”的Account对象,并将其名字和电话号码显示在页面中,则不光需要前端的功能,也需要和Apex类进行通信,从数据库中查询并得到数据。

    要实现这个功能,需要完成以下几个方面:

    • 准备Apex类和函数,能查询并返回对象的内容
    • 在组件中定义属性,类型为sObject对象,并将组件中的某些元素绑定到该对象的字段中
    • 将组件与Apex类联系起来
    • 在组件中调用Apex函数,接收Apex函数的执行结果,并更新组件中的属性

    准备Apex类和函数

    如果要使一个Apex函数可以被Lightning组件调用,则必须满足两点:

    1. 该函数的定义包含“@AuraEnabled”注解
    2. 该函数是静态类型

    现在建立相应的Apex类和函数:

    public class LightningAccountController {
    	@AuraEnabled
        public static Account getAccount(String name) {
            List<Account> accountList = [SELECT Id, Name, Phone 
                                         FROM Account
                                         WHERE Name LIKE :name
                                        ];
            if(accountList.size() > 0) {
                return accountList[0];
            } else {
                return null;
            }
        }
    }
    

    在组件中定义属性

    在“helloworld”组件中,定义一个类型为Account的属性:

    <aura:attribute name="account" type="Account" />
    
    <ui:button label="Get Account" press="{!c.handleClick}" />
        	
    <p>
        <ui:outputText value="{!v.account.Name}" />
    </p>
    
    <p>
        <ui:outputText value="{!v.account.Phone}" />
    </p>
    

    将组件与Apex类联系起来

    组件与Apex类联系的方式是在“aura:component”标签中设置“controller”属性为Apex类的名字:

    <aura:component controller="LightningAccountController">
    

    在组件中调用Apex函数,接收Apex函数的执行结果,并更新组件中的属性

    在组件中调用Apex函数,需要通过控制器文件。

    在“helloworldController.js”文件中修改“handleClick()”函数为:

    handleClick : function(component, event, helper) {
        // 1. 声明Apex类中的函数名
        var action = component.get("c.getAccount");
    
        // 2. 设置Apex函数的参数
        // 通常参数的值可以从组件中得到,比如使用component.get('v.userInput')
        action.setParams({
            "name": 'GenePoint'
        });
    
        // 3. 设置Apex函数执行完成后的功能
        action.setCallback(this, function(response) {
            // 得到Apex的结果状态
            var state = response.getState();
    
            if (state === "SUCCESS") {
                // 得到Apex的结果,结果可以是基本类型,也可以是sObject或集合类型等
                var result = response.getReturnValue();
    
                component.set('v.account', result);
            } else {
                // 错误处理
                // Do nothing
            }
        });
    
        // 4. 开始调用Apex函数
        $A.enqueueAction(action);
    }
    

    代码解释:

    1. 调用Apex函数需要四步,当然,如果Apex函数中没有参数,则第二步可以省略。
    2. Apex函数的调用是异步执行的,所以在上面的代码中,当执行了Apex函数之后,如果还有其他的代码,其他的代码有可能比“action.setCallback()”函数里的代码先执行,所以不能用“action.setCallback()”里的变量去决定“$A.enqueueAction(action);”语句之后的代码。
    3. 在Apex函数执行结束后,需要检测结果的状态,并且使用“getReturnValue()”函数来得到返回的结果。返回的结果无需类型转换,可以直接赋值给组件中的属性。
    4. $A是系统提供的一个全局变量,包含了一些重要的功能和服务。

    至此,运行应用的话,点击按钮“Get Account”,屏幕上会给出查询到的Account对象的结果。

    Lightning应用运行结果

    事件(Event)和句柄(Handler)

    在以上的例子中,所有的组件外观和逻辑(除了Apex部分)都是在一个组件中。在开发的过程中,这样做或许比较方便,但是有一个缺点,就是前端控制器中的逻辑只能被这一个组件使用。

    如果有一个公用的方法,每个组件都可以使用,那么该方法就会变得可重用,提高了代码的效率。

    Lightning中的事件(Event)和句柄(Handler)就实现了这种功能。

    事件和句柄有以下几个特性:

    1. 事件需要单独定义,独立于任何组件。
    2. 每个组件都可以注册事件,从而取得事件的使用权。
    3. 在组件中可以设置句柄,句柄中可以设定具体某个事件,从而声明此组件对于某个事件会进行处理。
    4. 在注册了事件的组件(A)使用事件时,系统会自动寻找包含该事件句柄的组件(B),从而自动调用B中的函数对事件进行处理。在这个过程中,组件A和B是相互独立的,并不需要知道对方具体的功能,而事件通过“广播”被自动进行了正确的处理。

    事件自动含有“type”属性,可以有两种值,“APPLICATION”和“COMPONENT”,表明了该事件被应用还是组件使用。

    还是以上面的“查找Account对象名字、电话并显示在屏幕上”的情况为例,重写组件,并通过事件和句柄将功能完成。

    分为以下几个步骤:

    1. 新建事件
    2. 建立事件触发组件
    3. 建立事件处理组件
    4. 在Lightning应用中包含事件处理组件

    新建事件

    在Developer Console中通过“File”菜单的“New”子菜单新建“Lightning Event”,命名为“FindAccount”。新建完成后,可以看到出现了“FindAccount.evt”的文件。将其中的代码修改为:

    <aura:event type="COMPONENT" description="Event template" >
        <aura:attribute name="accountName" type="String" />
    </aura:event>
    

    重要的是将默认的“type”属性值改为“COMPONENT”,让此事件对组件有效。

    事件中包含了一个属性“accountName”,用于接收要查询的Account对象的名字。

    建立事件触发组件

    要执行一个事件,必须要有事件的触发组件和事件的处理组件。前者使用“aura:registerEvent”触发事件,后者使用“aura:handler”处理事件。二者也可以被定义在同一个组件中。

    在Developer Console中新建组件,命名为“FindAccountEventRegister”。新建完成后,修改代码如下:

    <aura:component >
        <aura:registerEvent name="findAccountEvent" type="c:FindAccount"/>
    
        <ui:button label="Get Account" press="{!c.handleClick}" />
    </aura:component>
    

    可以看到,组件中注册了事件,并且只有一个按钮,用来点击并触发事件。

    在其控制器文件中写入“handleClick()”函数:

    handleClick : function(component, event, helper) {
        var cmpEvent = component.getEvent('findAccountEvent');
        
        cmpEvent.setParams({
            "accountName": 'GenePoint'
        });
        
        cmpEvent.fire();
    }
    

    这段代码主要就是使用“component.getEvent()”函数得到组件中注册的事件,再给事件中定义的属性赋值,最后通过“fire()”函数触发事件。

    建立事件处理组件

    新建组件,命名为“FindAccountEventHandler”。新建完成后,修改代码如下:

    <aura:component controller="LightningAccountController">
    	<aura:attribute name="account" type="Account" />
    	
        <aura:handler name="findAccountEvent" event="c:FindAccount" action="{!c.handleEvent}"/>
    
        <c:FindAccountEventRegister />
        
        <p>
            <ui:outputText value="{!v.account.Name}" />
        </p>
        
        <p>
            <ui:outputText value="{!v.account.Phone}" />
        </p>
    </aura:component>
    

    代码解释:

    1. 组件中定义了一个类型为Account的属性,并在“p”标签中显示该属性的字段值。
    2. 组件连接了之前的例子中建立好的Apex类,从而可以调用其中的函数从数据库查找Account对象。
    3. 组件中使用“aura:handler”定义了事件的处理方式,并包含了“FindAccountEventRegister”组件。这里有个地方很重要:“aura:handler”的“name”属性值和“FindAccountEventRegister”组件中“aura:registerEvent”的“name”属性值是一样的(findAccountEvent),这就保证了在事件触发时,事件与两个组件之间都有关联。
    4. 组件中的“aura:handler”里定义了“action”属性,其作用是当接收到事件触发的消息时,调用控制器中相应的函数来处理事件。

    在控制器文件中加入如下代码:

    handleEvent : function(component, event, helper) {
        var accountName = event.getParam('accountName');
    
        // 调用Apex类的函数来查询Account对象并在组件中显示结果
        var action = component.get("c.getAccount");
        action.setParams({
            "name": accountName
        });
        action.setCallback(this, function(response) {
            var state = response.getState();
    
            if (state === "SUCCESS") {
                var result = response.getReturnValue();
    
                component.set('v.account', result);
            } else {
                // Do nothing
            }
        });
    
        $A.enqueueAction(action);
    }
    

    这里的重点是通过“event.getParam()”函数来得到事件中属性的值。通过这个函数,在事件触发组件(FindAccountEventRegister)中设置的事件的属性值就被传递到了事件处理组件(FindAccountEventHandler),并进行下一步的处理。

    在Lightning应用中包含事件处理组件

    在Lightning应用中包含事件处理组件(FindAccountEventHandler)。运行该应用,点击按钮,即可看到查询的Account对象的结果和信息。至此,事件和句柄的基本功能就完成了。

    从这个例子中可以看出,事件可以将逻辑和输入分离,使得每个组件包含的功能尽可能少,增加重用性,提高开发效率。

    小结

    通过上面的例子,我们主要阐述了Lightning组件的基本实现方法,并通过事件和句柄来实现了组件之间的通信。

    Lightning框架的前端部分主要基于aura框架,如果对其他前端框架(Vue,React)已经有了了解,上手Lightning会非常容易。

  • 相关阅读:
    集合的泛型
    Strom的集群停止以及启动
    Strom简介,以及安装,和官方案例测试
    089实战 Nginx的安装
    088实战 项目技术框架
    087实战 集群的规模
    086实战 项目开发流程,以及什么是数据分析平台,再者为什么要做数据分析平台,数据来源,数据处理流程
    085 HBase的二级索引,以及phoenix的安装(需再做一次)
    084 HBase的数据迁移(含HDFS的数据迁移)
    083 HBase的完全分布式的搭建与部署,以及多master
  • 原文地址:https://www.cnblogs.com/zhuzhubaoya/p/14053963.html
走看看 - 开发者的网上家园