開發AEM Screens的自訂元件

下列教學課程將逐步說明為AEM Screens建立自訂元件的步驟。 AEM Screens會重複使用其他AEM產品的許多現有設計樣式和技術。 本教學課程強調針對AEM Screens進行開發時的差異和特殊考量。

概覽

本教學課程適用於剛接觸AEM Screens的開發人員。 在本教學課程中,AEM Screens中為「序列」頻道建立簡單的「Hello World」元件。 對話方塊可讓作者更新顯示的文字。

超視低音

必備條件

要完成本教學課程,需要以下內容:

  1. AEM 6.5AEM 6.3 +最新螢幕功能套件

  2. AEM Screens 播放器

  3. 當地開發環境

教學課程步驟和螢幕擷取是使用​CRXDE-Lite​來執行。 IDE也可用於完成教學課程。 有關使用IDE來開發和AEM的詳細資訊,請參閱這裡。

項目設定

畫面專案的原始碼通常會管理為多模組Maven專案。 為加速教學課程,專案是使用AEM專案原型13預先產生。 有關使用Maven AEM Project Archetype建立項目的詳細資訊,請參閱

  1. 使用CRX軟體包管理器下載並安裝以下軟體包:

    取得檔案

    取得檔案
    如果 使用Eclipse或其他IDE,則可選擇下載以下源包。使用Maven命令將專案部署至本機AEM例項:

    mvn -PautoInstallPackage clean install

    開始HelloWorld SRC螢幕We.Retail運行項目

    取得檔案

  2. CRX Package Manager中,驗證是否安裝了以下兩個軟體包:

    1. screens-weretail-run.ui.content-0.0.1-SNAPSHOT.zip
    2. screens-weretail-run.ui.apps-0.0.1-SNAPSHOT.zip

    透過CRX Package Manager安裝的螢幕We.Retail執行Ui.Apps和Ui.Content套件

    透過CRX Package Manager安裝的螢幕We.Retail執行Ui.Apps和Ui.Content套件

  3. screens-weretail-run.ui.apps​套件會在/apps/weretail-run下方安裝程式碼。

    此套件包含負責為專案產生自訂元件的程式碼。 此套件包含元件程式碼和所需的任何JavaScript或CSS。 此套件也內嵌​screens-weretail-run.core-0.0.1-SNAPSHOT.jar,其中包含專案所需的任何Java程式碼。

    注意

    在本教學課程中,不編寫Java程式碼。 如果需要更複雜的商業邏輯,可使用核心Java套件來建立和部署後端Java。

    在CRXDE Lite中呈現ui.apps程式碼

    在CRXDE Lite中呈現ui.apps程式碼

    helloworld​元件目前只是預留位置。 在本教學課程中,將會新增功能,讓作者更新元件顯示的訊息。

  4. screens-weretail-run.ui.content​套件會在下方安裝程式碼:

    • /conf/we-retail-run
    • /content/dam/we-retail-run
    • /content/screens/we-retail-run

    此套件包含專案所需的開始內容和設定結構。 /conf/we-retail-run 包含We.Retail Run專案的所有設定。/content/dam/we-retail-run 包括啟動專案的數位資產。/content/screens/we-retail-run 包含「畫面」內容結構。這些路徑下方的內容主要會在AEM中更新。 為了提高環境(本地、開發、舞台、prod)之間的一致性,通常在原始碼控制中保存基本內容結構。

  5. 導覽至「AEM畫面> We.Retail Run」專案:

    從「AEM開始功能表>按一下畫面圖示」。 驗證是否可以看到We.Retail Run Project。

    我們的"入門"

建立Hello World元件

Hello World元件是一個簡單元件,允許用戶輸入要顯示在螢幕上的消息。 此元件以AEM Screens元件範本為基礎:https://github.com/Adobe-Marketing-Cloud/aem-screens-component-template

AEM Screens有一些有趣的限制條件,這對於傳統的WCM Sites元件不一定適用。

  • 大部分的「螢幕」元件需要在目標數位標牌裝置上全螢幕執行
  • 大部分的「畫面」元件必須可內嵌在序列頻道中,才能產生投影片
  • 撰寫應允許編輯序列頻道中的個別元件,因此不需要全螢幕呈現
  1. 在​CRXDE-Lite http://localhost:4502/crx/de/index.jsp(或您選擇的IDE)中,導覽至/apps/weretail-run/components/content/helloworld.

    將以下屬性添加到helloworld元件:

        jcr:title="Hello World"
        sling:resourceSuperType="foundation/components/parbase"
        componentGroup="We.Retail Run - Content"
    

    /apps/weretail-run/components/content/helloworld的屬性

    /apps/weretail-run/components/content/helloworld的屬性

    該​helloworld​元件延伸該​foundation/components/parbase​元件,以便該元件能夠正確地用於序列通道中。

  2. /apps/weretail-run/components/content/helloworld下建立名為helloworld.html.的檔案

    在檔案中填入下列項目:

    <!--/*
    
     /apps/weretail-run/components/content/helloworld/helloworld.html
    
    */-->
    
    <!--/* production: preview authoring mode + unspecified mode (i.e. on publish) */-->
    <sly data-sly-test.production="${wcmmode.preview || wcmmode.disabled}" data-sly-include="production.html" />
    
    <!--/* edit: any other authoring mode, i.e. edit, design, scaffolding, etc. */-->
    <sly data-sly-test="${!production}" data-sly-include="edit.html" />
    

    畫面元件需要兩種不同的轉譯,視使用的編寫模式而定:

    1. 生產:預覽或發佈模式(wcmmode=disabled)
    2. 編輯:用於所有其他製作模式,例如編輯、設計、腳手架、開發人員……

    helloworld.html當做交換機,檢查哪個編寫模式目前處於活動狀態並重新導向至另一個HTL指令碼。畫面元件使用的常見慣例是,有edit.html指令碼用於編輯模式,而有production.html指令碼用於生產模式。

  3. /apps/weretail-run/components/content/helloworld下建立名為production.html.的檔案

    在檔案中填入下列項目:

    <!--/*
     /apps/weretail-run/components/content/helloworld/production.html
    
    */-->
    
    <div data-duration="${properties.duration}" class="cmp-hello-world">
     <h1 class="cmp-hello-world__message">${properties.message}</h1>
    </div>
    

    以上是Hello World元件的生產標籤。 由於元件用於序列通道,因此包含data-duration屬性。 序列通道使用data-duration屬性來瞭解序列項的顯示時間。

    元件會轉譯具有文字的divh1標籤。 ${properties.message} 是HTL指令碼的一部分,將輸出名為的JCR屬性的內容 message。稍後將建立一個對話框,允許用戶為message屬性文本輸入值。

    另請注意,BEM(塊元素修飾詞)注釋與元件一起使用。 BEM是CSS編碼慣例,可讓您更輕鬆地建立可重複使用的元件。 BEM是AEM的核心元件使用的符號。 如需詳細資訊,請參閱:https://getbem.com/

  4. /apps/weretail-run/components/content/helloworld下建立名為edit.html.的檔案

    在檔案中填入下列項目:

    <!--/*
    
     /apps/weretail-run/components/content/helloworld/edit.html
    
    */-->
    
    <!--/* if message populated */-->
    <div
     data-sly-test.message="${properties.message}"
     class="aem-Screens-editWrapper cmp-hello-world">
     <p class="cmp-hello-world__message">${message}</p>
    </div>
    
    <!--/* empty place holder */-->
    <div data-sly-test="${!message}"
         class="aem-Screens-editWrapper cq-placeholder cmp-hello-world"
         data-emptytext="${'Hello World' @ i18n, locale=request.locale}">
    </div>
    

    以上是Hello World元件的編輯標籤。 如果已填入對話訊息,第一個區塊會顯示元件的編輯版本。

    如果未輸入對話消息,則呈現第二塊。 cq-placeholderdata-emptytext將標籤​Hello World​轉換為該情況下的預留位置。 標籤的字串可以使用i18n進行國際化,以支援在多個地區設定中編寫。

  5. Copy Screens Image Dialog to be used for the Hello World component.

    從現有對話方塊開始進行修改最簡單。

    1. 從以下位置複製對話框:/libs/screens/core/components/content/image/cq:dialog
    2. 將對話框貼上到/apps/weretail-run/components/content/helloworld下面

    copy-image-dialog

  6. 更新「Hello World」對話框以包含消息的頁籤。

    更新對話方塊,使其符合下列項目。 XML中顯示最終對話框的JCR節點結構如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <jcr:root xmlns:sling="https://sling.apache.org/jcr/sling/1.0" xmlns:cq="https://www.day.com/jcr/cq/1.0" xmlns:jcr="https://www.jcp.org/jcr/1.0" xmlns:nt="https://www.jcp.org/jcr/nt/1.0"
        jcr:primaryType="nt:unstructured"
        jcr:title="Hello World"
        sling:resourceType="cq/gui/components/authoring/dialog">
        <content
            jcr:primaryType="nt:unstructured"
            sling:resourceType="granite/ui/components/coral/foundation/tabs"
            size="L">
            <items jcr:primaryType="nt:unstructured">
                <message
                    jcr:primaryType="nt:unstructured"
                    jcr:title="Message"
                    sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns">
                    <items jcr:primaryType="nt:unstructured">
                        <column
                            jcr:primaryType="nt:unstructured"
                            sling:resourceType="granite/ui/components/coral/foundation/container">
                            <items jcr:primaryType="nt:unstructured">
                                <message
                                    jcr:primaryType="nt:unstructured"
                                    sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                    fieldDescription="Message for component to display"
                                    fieldLabel="Message"
                                    name="./message"/>
                            </items>
                        </column>
                    </items>
                </message>
                <sequence
                    jcr:primaryType="nt:unstructured"
                    jcr:title="Sequence"
                    sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns">
                    <items jcr:primaryType="nt:unstructured">
                        <column
                            jcr:primaryType="nt:unstructured"
                            sling:resourceType="granite/ui/components/coral/foundation/container">
                            <items jcr:primaryType="nt:unstructured">
                                <duration
                                    jcr:primaryType="nt:unstructured"
                                    sling:resourceType="granite/ui/components/coral/foundation/form/numberfield"
                                    defaultValue=""
                                    fieldDescription="Amount of time the image will be shown in the sequence, in milliseconds"
                                    fieldLabel="Duration (ms)"
                                    min="0"
                                    name="./duration"/>
                            </items>
                        </column>
                    </items>
                </sequence>
            </items>
        </content>
    </jcr:root>
    

    消息的文本欄位將保存到名為message的屬性中,並且持續時間的數字欄位將保存到名為duration的屬性中。 HTL在/apps/weretail-run/components/content/helloworld/production.html中將這兩個屬性都參照為${properties.message}${properties.duration}

    Hello World —— 已完成對話方塊

    Hello World —— 已完成對話方塊

建立客戶端庫

用戶端程式庫提供組織和管理AEM實作所需CSS和JavaScript檔案的機制。

AEM Screens元件在「編輯」模式與「預覽/生產」模式的轉譯方式不同。 將會建立兩個用戶端程式庫,一個用於編輯模式,另一個用於預覽/生產。

  1. 為Hello World元件的客戶端庫建立資料夾。

    /apps/weretail-run/components/content/helloworld下方建立名為clientlibs的新資料夾。

    2018-04-30_at_1046am

  2. clientlibs資料夾下,建立一個名為shared的新節點,該節點類型為cq:ClientLibraryFolder.

    2018-04-30_at_1115am

  3. 將下列屬性新增至共用用戶端程式庫:

    • allowProxy | 布林函數 | true

    • categories|字串[] | cq.screens.components

    /apps/weretail-run/components/content/helloworld/clientlibs/shared的屬性

    /apps/weretail-run/components/content/helloworld/clientlibs/shared的屬性

    類別屬性是識別用戶端程式庫的字串。 cq.screens.components類別可在「編輯」和「預覽/生產」模式中使用。 因此,在sharedclientlib中定義的任何CSS/JS都會以所有模式載入。

    絕對不要在生產環境中直接將任何路徑顯示至/app,這是最佳做法。 allowProxy屬性可確保用戶端程式庫CSS和JS是透過首碼of/etc.clientlibs來參考。

  4. 在共用資料夾下方建立名為css.txt的檔案。

    在檔案中填入下列項目:

    #base=css
    
    styles.less
    
  5. shared資料夾下建立名為css的資料夾。 在css資料夾下添加名為style.less的檔案。 用戶端程式庫的結構現在應如下所示:

    2018-04-30_at_3_11pm

    本教學課程不使用LESS直接編寫CSS。 LESS 是常用的CSS預編譯器,可支援CSS變數、混合和函式。AEM用戶端程式庫本身支援LESS編譯。 Sass或其他預先編譯器可使用,但需在AEM以外進行編譯。

  6. /apps/weretail-run/components/content/helloworld/clientlibs/shared/css/styles.less填入以下內容:

    /**
        Shared Styles
       /apps/weretail-run/components/content/helloworld/clientlibs/shared/css/styles.less
    
    **/
    
    .cmp-hello-world {
        background-color: #fff;
    
     &__message {
      color: #000;
      font-family: Helvetica;
      text-align:center;
     }
    }
    
  7. 複製並貼上shared客戶端庫資料夾,以建立名為production的新客戶端庫。

    複製共用用戶端程式庫以建立新的生產用戶端程式庫

    複製共用用戶端程式庫以建立新的生產用戶端程式庫

  8. 將生產客戶端庫的categories屬性更新為cq.screens.components.production.

    這可確保只有在「預覽/生產」模式下才載入樣式。

    /apps/weretail-run/components/content/helloworld/clientlibs/production的屬性

    /apps/weretail-run/components/content/helloworld/clientlibs/production的屬性

  9. /apps/weretail-run/components/content/helloworld/clientlibs/production/css/styles.less填入以下內容:

    /**
        Production Styles
       /apps/weretail-run/components/content/helloworld/clientlibs/production/css/styles.less
    
    **/
    .cmp-hello-world {
    
        height: 100%;
        width: 100%;
        position: fixed;
    
     &__message {
    
      position: relative;
      font-size: 5rem;
      top:25%;
     }
    }
    

    上述樣式會將訊息置於畫面中央,但只會顯示在生產模式中。

第三個clientlibrary類別:cq.screens.components.edit可用來新增僅限編輯的特定樣式至元件。

Clientlib類別 使用狀況
cq.screens.components 在編輯和生產模式之間共用的樣式和指令碼
cq.screens.components.edit 僅用於編輯模式的樣式和指令碼
cq.screens.components.production 僅用於生產模式的樣式和指令碼

建立設計頁面

AEM Screens使用靜態頁面範本設計組態進行全域變更。 設計配置常用於為通道上的Parsys配置允許的元件。 最佳實務是以應用程式特定的方式儲存這些設定。

在「We.Retail Run Design」(We.Retail Run設計)頁面下建立,該頁面將儲存We.Retail Run項目的所有特定配置。

  1. 在​CRXDE-Lite http://localhost:4502/crx/de/index.jsp#/apps/settings/wcm/designs中,導覽至/apps/settings/wcm/designs

  2. 在設計資料夾下方建立新節點,名為we-retail-run,類型為cq:Page

  3. we-retail-run頁面下,添加另一個名為jcr:content的節點,該節點類型為nt:unstructured。 將以下屬性添加到jcr:content節點:

    名稱 類型
    jcr:title 字串 We.Retail Run
    sling:resourceType 字串 wcm/core/components/designer
    cq:doctype 字串 html_5

    設計頁面,網址為:/apps/settings/wcm/designs/we-retail-run

    設計頁面,網址為:/apps/settings/wcm/designs/we-retail-run

建立序列通道

Hello World元件用於序列通道。 若要測試元件,會建立新的「序列頻道」。

  1. 從「AEM開始」選單導覽至「Screens > We.Retail Ru n >」,然後選取「Channels」。

  2. 按一下​建立​按鈕

    1. 選擇​建立實體

    2018-04-30_at_5_18pm

  3. 在建立嚮導中:

  4. 模板步驟——選擇​序列通道

    1. 屬性步驟
    • 基本頁籤>標題= 空閒通道
    • 渠道頁籤>選中​使渠道聯機

    空閒通道

  5. 開啟閒置頻道的頁面屬性。 更新「設計」欄位,以指向在上一節中建立的/apps/settings/wcm/designs/we-retail-run,設計頁面。

    設計設定/apps/settings/wcm/designs/we-retail-run

    指向/apps/settings/wcm/designs/we-retail-run的設計組態

  6. 編輯新建立的閒置頻道以開啟它。

  7. 將頁面模式切換為​Design​模式

    1. 按一下Parsys中的​wrnch​圖示,以設定允許的元件

    2. 選擇​Screens​群組和​We.Retail Run - Content​群組。

    2018-04-30_at_5_43pm

  8. 將頁面模式切換為​Edit。 Hello World元件現在可以新增至頁面,並與其他序列頻道元件結合。

    2018-04-30_at_5_53pm

  9. 在​中,CRXDE-Lite http://localhost:4502/crx/de/index.jsp#/apps/settings/wcm/designs/we-retail-run/jcr%3Acontent/sequencechannel/par導航至/apps/settings/wcm/designs/we-retail-run/jcr:content/sequencechannel/par。 請注意,components屬性現在包含group:Screensgroup:We.Retail Run - Content

    在/apps/settings/wcm/designs/we-retail-run下進行設計設定

    在/apps/settings/wcm/designs/we-retail-run下進行設計設定

自定義處理程式的模板

如果您的自訂元件使用外部資源(例如資產(影像、視訊、字型、圖示等)、特定資產轉譯或用戶端資料庫(css、js等),則這些不會自動新增至離線設定,因為我們預設只會打包HTML標籤。

為了讓您自訂並最佳化下載至播放器的確切資產,我們提供自訂元件的擴充功能機制,讓自訂元件在「畫面」中顯示其依存性至離線快取邏輯。

下節將展示自訂離線資源處理常式的範本,以及該特定專案的pom.xml最低需求。

package …;

import javax.annotation.Nonnull;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;

import com.adobe.cq.screens.visitor.OfflineResourceHandler;

@Service(value = OfflineResourceHandler.class)
@Component(immediate = true)
public class MyCustomHandler extends AbstractResourceHandler {

 @Reference
 private …; // OSGi services injection

 /**
  * The resource types that are handled by the handler.
  * @return the handled resource types
  */
 @Nonnull
 @Override
 public String[] getSupportedResourceTypes() {
     return new String[] { … };
 }

 /**
  * Accept the provided resource, visit and traverse it as needed.
  * @param resource The resource to accept
  */
 @Override
 public void accept(@Nonnull Resource resource) {
     ValueMap properties = ResourceUtil.getValueMap(resource);
     
     /* You can directly add explicit paths for offline caching using the `visit`
        method of the visitor. */
     
     // retrieve a custom property from the component
     String myCustomRenditionUrl = properties.get("myCustomRenditionUrl", String.class);
     // adding that exact asset/rendition/path to the offline manifest
     this.visitor.visit(myCustomRenditionUrl);
     
     
     /* You can delegate handling for dependent resources so they are also added to
        the offline cache using the `accept` method of the visitor. */
     
     // retrieve a referenced dependent resource
     String referencedResourcePath = properties.get("myOtherResource", String.class);
     ResourceResolver resolver = resource.getResourceResolver();
     Resource referencedResource = resolver.getResource(referencedResourcePath);
     // let the handler for that resource handle it
     if (referencedResource != null) {
         this.visitor.accept(referencedResource);
     }
   }
}

以下代碼提供pom.xml中該特定項目的最低要求:

   <dependencies>
        …
        <!-- Felix annotations -->
        <dependency>
            <groupId>org.apache.felix</groupId>
            <artifactId>org.apache.felix.scr.annotations</artifactId>
            <version>1.9.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- Screens core bundle with OfflineResourceHandler/AbstractResourceHandler -->
        <dependency>
            <groupId>com.adobe.cq.screens</groupId>
            <artifactId>com.adobe.cq.screens</artifactId>
            <version>1.5.90</version>
            <scope>provided</scope>
        </dependency>
        …
      </dependencies>

將所有內容整合在一起

以下視訊顯示完成的元件,以及如何將它新增至「序列」頻道。 接著,「頻道」會新增至「位置」顯示畫面,並最終指派給「畫面」播放器。

完成代碼

以下是教學課程中完成的程式碼。 screens-weretail-run.ui.apps-0.0.1-SNAPSHOT.zip​和​screens-weretail-run.ui.content-0.0.1-SNAPSHOT.zip​是編譯的AEM套件。 SRC-screens-weretail-run-0.0.1.zip 是可使用Maven部署的未編譯原始碼。

取得檔案

取得檔案

取得檔案

本頁內容