Lightning 組件基礎知識

Lightning框架簡介

Lightning框架是Salesforce提供的一套基于用戶界面的開發(fā)框架,對于開發(fā)單頁面應用(Single Page Application)有很大的幫助。它和Visualforce可以共存,但開發(fā)的方法并不相同。

Lightning有單獨的前端架構,基于名叫aura的框架,主要包括:

  • 組件:由XML語言開發(fā)的用戶界面,組件內部可以包含其他組件和標準的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組件相關列表

在編輯區(qū)域中,系統(tǒng)已經默認生成了一段代碼:

<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應用中,系統(tǒng)也生成了默認的代碼:

<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”,系統(tǒng)會自動建立“helloworld.css”文件。開發(fā)者可以在此文件中修改CSS樣式。

要注意的是,不同于普通的CSS文件,在整個文件中,每一個樣式必須帶有“.THIS”,它的作用是保證新建的樣式只對當前的組件有效。

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

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

保存后再次運行應用,可以看到顯示的文字樣式已經變化了。

Lightning組件的CSS更改效果

為組件添加屬性

現在的“helloworld”組件只能顯示一段靜態(tài)文字。如果需要增加其他動態(tài)功能,比如自定義顯示文字的內容,則必須要用到組件的“屬性”。

每個組件可以包含若干“屬性”。組件的屬性可以看作是包含在組件內的變量,它們可以是任何類型。當組件載入后,組件的屬性值會被初始化,組件的控制器也可以更改屬性的值。組件的屬性可以被綁定在組件內部的元素中,從而實現動態(tài)功能。

組件的屬性要定義在“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!”變?yōu)榱恕癏ello world! - test user”。

由于屬性和組件的元素相互綁定,如果在應用運行時更改屬性“message”的值,那么顯示的文字也會相應的發(fā)生變化。

數據提供者

在組件中,如果想綁定一個屬性,需要用“{!v.屬性名}”的語法。其中的“v”被稱為數據提供者(Value Provider)。如果想在組件中顯示稍微復雜的表達式而非單獨的屬性值,同樣可以用“{! }”表達式。

比如在Lightning框架中提供了一個標準顯示文字的組件“ui:outputText”,設置其“value”屬性即可顯示相應的文字。在“helloworld”中可以將代碼變?yōu)椋?/p>

<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}" />

循環(huán)讀取集合類型屬性的值

當一個屬性是集合類型時,比如字符串的列表,在組件中可以使用標準組件“aura:iteration”遍歷其每一個元素。

比如:

<aura:attribute name="textList" 
                type="List" 
                default="['text 1',
                            'text 2',
                            'text 3']" />

<!--在組件循環(huán)顯示字符串-->
<aura:iteration items="{! v.textList }" var="singleText">
    <p> {! singleText } </p>
</aura:iteration>

在上面的代碼中,使用了標準元素“aura:iteration”。我們將字符串列表屬性“textList”綁定到循環(huán)列表屬性“items”中,并定義“singleText”為每一個循環(huán)中列表中變量的名字,類似于“for(String singleText : textList)”。在循環(huán)組件的內部,使用“{! }”表達式顯示每一個循環(huán)元素的內容,注意這里不需要使用“v”了。

為組件添加功能

假設在“helloworld”中,需要增加一個按鈕,點擊之后屬性“message”要發(fā)生變化。

用標準組件“ui:button”可以添加按鈕,要想實現點擊按鈕之后更改屬性的功能,就必須使用前端控制器。

在Developer Console的右側列表中,點擊“CONTROLLER”,系統(tǒng)會自動建立一個前端控制器文件“helloworldController.js”。它是一個JavaScript文件,開發(fā)者可以在其中添加JS函數實現功能。

在Developer Console的右側列表中,點擊“HELPER”,系統(tǒng)會自動建立一個輔助函數文件“helloworldHelper.js”。它是一個JavaScript文件,開發(fā)者可以在其中添加JS函數,這些函數可以從控制器文件中調用。

另外要注意的是,在控制器文件中,如果定義了若干函數,它們之間不能互相調用。所以必須將某些公共的功能挪到輔助函數文件中,再使用“helper.函數名”來調用功能。

在控制器文件中增加一個“handleClick”函數,更改組件中“message”屬性的值:

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

在組件的外觀中增加一個按鈕,點擊之后執(zhí)行“handleClick”函數:

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

其中“l(fā)abel”是要在按鈕上顯示的文字,“press”是一個事件,當點擊按鈕后,調用“press”里定義的函數。

注意,這里使用了“{!c.函數名}”的方式來調用JS控制器中的函數,其中的“c”便是代表了“Controller”。

運行應用,當點擊了按鈕之后,屏幕上顯示的文字便從“Hello world! - test user”變成了“Hello world! - Updated Message!”。

控制器函數詳解

每一個控制器的函數都默認帶有三個參數:

  • component:代表了當前的組件
  • event:代表了觸發(fā)的事件
  • 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();
}

如果想得到觸發(fā)某函數的組件元素的內容,則需要使用event參數。

比如在組件中有一個按鈕,點擊會觸發(fā)控制器中的“handleClick()”函數。在“handleClick()”函數中,使用“event.getSource()”即可得到按鈕元素。

組件中的設置:

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

控制器中:

handleClick : function(component, event, helper) {
    // 得到組件中的按鈕元素
    var buttonClicked = event.getSource();

    // 得到組件中按鈕元素的“l(fā)abel”屬性
    var buttonValue = buttonClicked.get('v.label');
    // buttonValue的值是“button text”
}

使用這種方式,可以直接得到組件中元素的各種屬性等。

組件和Apex通信

在“helloworld”組件中,如果想要通過點擊按鈕,從數據庫中讀取一個名叫“GenePoint”的Account對象,并將其名字和電話號碼顯示在頁面中,則不光需要前端的功能,也需要和Apex類進行通信,從數據庫中查詢并得到數據。

要實現這個功能,需要完成以下幾個方面:

  • 準備Apex類和函數,能查詢并返回對象的內容
  • 在組件中定義屬性,類型為sObject對象,并將組件中的某些元素綁定到該對象的字段中
  • 將組件與Apex類聯系起來
  • 在組件中調用Apex函數,接收Apex函數的執(zhí)行結果,并更新組件中的屬性

準備Apex類和函數

如果要使一個Apex函數可以被Lightning組件調用,則必須滿足兩點:

  1. 該函數的定義包含“@AuraEnabled”注解
  2. 該函數是靜態(tài)類型

現在建立相應的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函數的執(zhí)行結果,并更新組件中的屬性

在組件中調用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函數執(zhí)行完成后的功能
    action.setCallback(this, function(response) {
        // 得到Apex的結果狀態(tài)
        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函數的調用是異步執(zhí)行的,所以在上面的代碼中,當執(zhí)行了Apex函數之后,如果還有其他的代碼,其他的代碼有可能比“action.setCallback()”函數里的代碼先執(zhí)行,所以不能用“action.setCallback()”里的變量去決定“$A.enqueueAction(action);”語句之后的代碼。
  3. 在Apex函數執(zhí)行結束后,需要檢測結果的狀態(tài),并且使用“getReturnValue()”函數來得到返回的結果。返回的結果無需類型轉換,可以直接賦值給組件中的屬性。
  4. $A是系統(tǒng)提供的一個全局變量,包含了一些重要的功能和服務。

至此,運行應用的話,點擊按鈕“Get Account”,屏幕上會給出查詢到的Account對象的結果。

Lightning應用運行結果

事件(Event)和句柄(Handler)

在以上的例子中,所有的組件外觀和邏輯(除了Apex部分)都是在一個組件中。在開發(fā)的過程中,這樣做或許比較方便,但是有一個缺點,就是前端控制器中的邏輯只能被這一個組件使用。

如果有一個公用的方法,每個組件都可以使用,那么該方法就會變得可重用,提高了代碼的效率。

Lightning中的事件(Event)和句柄(Handler)就實現了這種功能。

事件和句柄有以下幾個特性:

  1. 事件需要單獨定義,獨立于任何組件。
  2. 每個組件都可以注冊事件,從而取得事件的使用權。
  3. 在組件中可以設置句柄,句柄中可以設定具體某個事件,從而聲明此組件對于某個事件會進行處理。
  4. 在注冊了事件的組件(A)使用事件時,系統(tǒng)會自動尋找包含該事件句柄的組件(B),從而自動調用B中的函數對事件進行處理。在這個過程中,組件A和B是相互獨立的,并不需要知道對方具體的功能,而事件通過“廣播”被自動進行了正確的處理。

事件自動含有“type”屬性,可以有兩種值,“APPLICATION”和“COMPONENT”,表明了該事件被應用還是組件使用。

還是以上面的“查找Account對象名字、電話并顯示在屏幕上”的情況為例,重寫組件,并通過事件和句柄將功能完成。

分為以下幾個步驟:

  1. 新建事件
  2. 建立事件觸發(fā)組件
  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對象的名字。

建立事件觸發(fā)組件

要執(zhí)行一個事件,必須要有事件的觸發(fā)組件和事件的處理組件。前者使用“aura:registerEvent”觸發(fā)事件,后者使用“aura:handler”處理事件。二者也可以被定義在同一個組件中。

在Developer Console中新建組件,命名為“FindAccountEventRegister”。新建完成后,修改代碼如下:

<aura:component >
    <aura:registerEvent name="findAccountEvent" type="c:FindAccount"/>

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

可以看到,組件中注冊了事件,并且只有一個按鈕,用來點擊并觸發(fā)事件。

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

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

這段代碼主要就是使用“component.getEvent()”函數得到組件中注冊的事件,再給事件中定義的屬性賦值,最后通過“fire()”函數觸發(fā)事件。

建立事件處理組件

新建組件,命名為“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),這就保證了在事件觸發(fā)時,事件與兩個組件之間都有關聯。
  4. 組件中的“aura:handler”里定義了“action”屬性,其作用是當接收到事件觸發(fā)的消息時,調用控制器中相應的函數來處理事件。

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

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()”函數來得到事件中屬性的值。通過這個函數,在事件觸發(fā)組件(FindAccountEventRegister)中設置的事件的屬性值就被傳遞到了事件處理組件(FindAccountEventHandler),并進行下一步的處理。

在Lightning應用中包含事件處理組件

在Lightning應用中包含事件處理組件(FindAccountEventHandler)。運行該應用,點擊按鈕,即可看到查詢的Account對象的結果和信息。至此,事件和句柄的基本功能就完成了。

從這個例子中可以看出,事件可以將邏輯和輸入分離,使得每個組件包含的功能盡可能少,增加重用性,提高開發(fā)效率。

小結

通過上面的例子,我們主要闡述了Lightning組件的基本實現方法,并通過事件和句柄來實現了組件之間的通信。

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

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現,斷路器,智...
    卡卡羅2017閱讀 136,551評論 19 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,007評論 25 709
  • 國家電網公司企業(yè)標準(Q/GDW)- 面向對象的用電信息數據交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 12,376評論 6 13
  • 不知道從什么時候開始微信群開始發(fā)紅包賭錢了,最開始的認知就是三五個好友搶最少的發(fā)紅包,慢慢的變成一人做莊一群人猜...
    裙擺閱讀 156評論 0 0
  • 炒股只做自己熟悉的板塊,熟悉的個股。不要吃著碗里,還看著鍋里。什么都想抓,結果什么都沒有抓到。最終追高買入,套在高...
    飛過無痕閱讀 584評論 0 0

友情鏈接更多精彩內容