擴充核心元件 extend-component

瞭解如何擴充與AEM SPA編輯器搭配使用的現有核心元件。 瞭解如何擴充現有元件是一項強大的技術,可自訂和擴充AEM SPA Editor實作的功能。

目標

  1. 使用其他屬性和內容擴充現有的核心元件。
  2. 瞭解使用sling:resourceSuperType的元件繼承基本知識。
  3. 瞭解如何為Sling模型使用委派模式以重複使用現有邏輯和功能。

您將建置的內容

在本章中,已建立新的Card元件。 Card元件擴充影像核心元件,新增其他內容欄位,例如「標題」和「行動號召」按鈕,以針對SPA內的其他內容執行Teaser的角色。

卡片元件的最終製作

NOTE
在真實世界的實作中,視專案需求而定,可能更適合使用Teaser元件,而不是擴充影像核心元件以產生Card元件。 建議您儘可能直接使用核心元件

先決條件

檢閱設定本機開發環境所需的工具和指示。

取得程式碼

  1. 透過Git下載本教學課程的起點:

    code language-shell
    $ git clone git@github.com:adobe/aem-guides-wknd-spa.git
    $ cd aem-guides-wknd-spa
    $ git checkout Angular/extend-component-start
    
  2. 使用Maven將程式碼庫部署到本機AEM執行個體:

    code language-shell
    $ mvn clean install -PautoInstallSinglePackage
    

    如果使用AEM 6.x,請新增classic設定檔:

    code language-shell
    $ mvn clean install -PautoInstallSinglePackage -Pclassic
    
  3. 安裝傳統WKND參考站台的完成套件。 由WKND參考網站提供的影像已在WKND SPA上重複使用。 可以使用AEM封裝管理員來安裝封裝。

    封裝管理員安裝wknd.all

您一律可以在GitHub上檢視完成的程式碼,或切換至分支Angular/extend-component-solution在本機簽出程式碼。

Inspect初始卡片實施

章節起始程式碼已提供初始卡片元件。 Inspect是資訊卡實作的起點。

  1. 在您選擇的IDE中,開啟ui.apps模組。

  2. 瀏覽至ui.apps/src/main/content/jcr_root/apps/wknd-spa-angular/components/card並檢視.content.xml檔案。

    卡片元件AEM定義開始

    code language-xml
    <?xml version="1.0" encoding="UTF-8"?>
    <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
        jcr:primaryType="cq:Component"
        jcr:title="Card"
        sling:resourceSuperType="wknd-spa-angular/components/image"
        componentGroup="WKND SPA Angular - Content"/>
    

    屬性sling:resourceSuperType指向wknd-spa-angular/components/image,表示Card元件繼承了WKND SPA Image元件的功能。

  3. Inspect檔案ui.apps/src/main/content/jcr_root/apps/wknd-spa-angular/components/image/.content.xml

    code language-xml
    <?xml version="1.0" encoding="UTF-8"?>
    <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
        jcr:primaryType="cq:Component"
        jcr:title="Image"
        sling:resourceSuperType="core/wcm/components/image/v2/image"
        componentGroup="WKND SPA Angular - Content"/>
    

    請注意,sling:resourceSuperType指向core/wcm/components/image/v2/image。 這表示WKND SPA影像元件繼承了核心元件影像的功能。

    也稱為Proxy模式 Sling資源繼承是一種強大的設計模式,可讓子元件繼承功能並在需要時擴充/覆寫行為。 Sling繼承支援多個層級的繼承,所以新Card元件最終會繼承核心元件影像的功能。

    許多開發團隊都會努力做到自我(請勿重複這點)。 Sling繼承可讓您在AEM中完成此操作。

  4. card資料夾下,開啟檔案_cq_dialog/.content.xml

    此檔案是Card元件的元件對話方塊定義。 如果使用Sling繼承,則可以使用Sling資源合併器的功能來覆寫或擴充對話方塊的部分。 在此範例中,對話方塊中已新增索引標籤,以從作者擷取其他資料並填入卡片元件。

    sling:orderBefore之類的屬性可讓開發人員選擇插入新標籤或表單欄位的位置。 在此情況下,Text索引標籤會插入asset索引標籤之前。 若要充分利用Sling Resource Merger,請務必瞭解影像元件對話方塊的原始對話方塊節點結構。

  5. card資料夾下,開啟檔案_cq_editConfig.xml。 此檔案指定AEM編寫UI中的拖放行為。 擴充影像元件時,資源型別必須符合元件本身。 檢閱<parameters>節點:

    code language-xml
    <parameters
        jcr:primaryType="nt:unstructured"
        sling:resourceType="wknd-spa-angular/components/card"
        imageCrop=""
        imageMap=""
        imageRotate=""/>
    

    大部分元件不需要cq:editConfig,影像和影像元件的子系下階是例外。

  6. 在IDE切換至ui.frontend模組,瀏覽至ui.frontend/src/app/components/card

    Angular元件開始

  7. Inspect檔案card.component.ts

    元件已經使用標準MapTo函式截斷,以對應到AEM Card元件。

    code language-js
    MapTo('wknd-spa-angular/components/card')(CardComponent, CardEditConfig);
    

    檢閱類別中srcalttitle的三個@Input引數。 這些是AEM元件中對應至Angular元件的預期JSON值。

  8. 開啟檔案card.component.html

    code language-html
    <div class="card"  *ngIf="hasContent">
        <app-image class="card__image" [src]="src" [alt]="alt" [title]="title"></app-image>
    </div>
    

    在此範例中,我們選擇透過從card.component.ts傳遞@Input引數來重複使用現有的Angular影像元件app-image。 在稍後的教學課程中,會新增並顯示其他屬性。

更新範本原則

使用此初始Card實作,檢閱AEM SPA編輯器中的功能。 若要檢視初始Card元件,需要更新範本原則。

  1. 將入門程式碼部署到AEM的本機執行個體(如果尚未部署):

    code language-shell
    $ cd aem-guides-wknd-spa
    $ mvn clean install -PautoInstallSinglePackage
    
  2. 瀏覽至http://localhost:4502/editor.html/conf/wknd-spa-angular/settings/wcm/templates/spa-page-template/structure.html的SPA頁面範本。

  3. 更新配置容器的原則以將新的Card元件新增為允許的元件:

    更新配置容器原則

    儲存原則的變更,並將Card元件視為允許的元件:

    卡片元件為允許的元件

作者初始卡片元件

接下來,使用AEM SPA編輯器編寫Card元件。

  1. 導覽至http://localhost:4502/editor.html/content/wknd-spa-angular/us/en/home.html

  2. Edit模式中,將Card元件新增至Layout Container

    插入新元件

  3. 將影像從資產尋找器拖放至Card元件上:

    新增影像

  4. 開啟Card元件對話方塊並注意已新增​ 文字 ​索引標籤。

  5. 在​ 文字 ​索引標籤上輸入下列值:

    文字元件索引標籤

    卡片路徑 — 在SPA首頁下選擇頁面。

    CTA文字 - 「瞭解詳情」

    卡片標題 — 留空

    從連結的頁面取得標題 — 勾選核取方塊以表示True。

  6. 更新​ 資產中繼資料 ​索引標籤以新增​ 替代文字 ​和​ 標題 ​的值。

    更新對話方塊後,目前沒有其他變更顯示。 若要將新欄位公開給Angular元件,我們需要更新Card元件的Sling模型。

  7. 開啟新索引標籤並導覽至CRXDE-Lite。 Inspect /content/wknd-spa-angular/us/en/home/jcr:content/root/responsivegrid下的內容節點以尋找Card元件內容。

    CRXDE-Lite元件屬性

    觀察對話方塊是否持續儲存屬性cardPathctaTexttitleFromPage

更新卡片Sling模型

若要最終將元件對話方塊中的值公開給Angular元件,我們需要更新為Card元件填入JSON的Sling模型。 我們也有機會實作兩種商業邏輯:

  • 如果titleFromPage為​ true,則傳回cardPath所指定頁面的標題,否則傳回cardTitle文字欄位的值。
  • 傳回cardPath所指定頁面的上次修改日期。

返回您選擇的IDE並開啟core模組。

  1. core/src/main/java/com/adobe/aem/guides/wknd/spa/angular/core/models/Card.java開啟檔案Card.java

    請注意,Card介面目前延伸com.adobe.cq.wcm.core.components.models.Image,因此繼承Image介面的方法。 Image介面已擴充ComponentExporter介面,可讓Sling模型匯出為JSON並由SPA編輯器對應。 因此,我們不需要像在自訂元件章節中那樣明確擴充ComponentExporter介面。

  2. 將下列方法新增至介面:

    code language-java
    @ProviderType
    public interface Card extends Image {
    
        /***
        * The URL to populate the CTA button as part of the card.
        * The link should be based on the cardPath property that points to a page.
        * @return String URL
        */
        public String getCtaLinkURL();
    
        /***
        * The text to display on the CTA button of the card.
        * @return String CTA text
        */
        public String getCtaText();
    
    
    
        /***
        * The date to be displayed as part of the card.
        * This is based on the last modified date of the page specified by the cardPath
        * @return
        */
        public Calendar getCardLastModified();
    
    
        /**
        * Return the title of the page specified by cardPath if `titleFromPage` is set to true.
        * Otherwise return the value of `cardTitle`
        * @return
        */
        public String getCardTitle();
    }
    

    這些方法會透過JSON模型API公開,並傳遞至Angular元件。

  3. 開啟CardImpl.java。 這是Card.java介面的實作。 為了加速教學課程,已部分解決此實作。 請注意是否使用@Model@Exporter註解,以確保Sling模型能夠透過Sling模型匯出工具序列化為JSON。

    CardImpl.java也對Sling模型使用委派模式以避免從影像核心元件重寫邏輯。

  4. 請注意下列各行:

    code language-java
    @Self
    @Via(type = ResourceSuperType.class)
    private Image image;
    

    上述註解會根據Card元件的sling:resourceSuperType繼承,將名為image的影像物件具現化。

    code language-java
    @Override
    public String getSrc() {
        return null != image ? image.getSrc() : null;
    }
    

    然後就可以直接使用image物件來實作Image介面定義的方法,而不需要自行撰寫邏輯。 此技巧用於getSrc()getAlt()getTitle()

  5. 接下來,實作initModel()方法,以根據cardPath的值起始私有變數cardPage

    code language-java
    @PostConstruct
    public void initModel() {
        if(StringUtils.isNotBlank(cardPath) && pageManager != null) {
            cardPage = pageManager.getPage(this.cardPath);
        }
    }
    

    初始化Sling模型時會呼叫@PostConstruct initModel(),因此您可以藉此機會初始化模型中其他方法可能使用的物件。 pageManager是透過@ScriptVariable註解提供給Sling模型使用的數個Java™支援的全域物件之一。 getPage方法接受路徑並傳回AEM Page物件,如果路徑未指向有效頁面,則傳回null。

    這會初始化cardPage變數,其他新方法會使用此變數來傳回基礎連結頁面的相關資料。

  6. 檢閱已對映至作者對話方塊所儲存JCR屬性的全域變數。 @ValueMapValue註解是用來自動執行對應。

    code language-java
    @ValueMapValue
    private String cardPath;
    
    @ValueMapValue
    private String ctaText;
    
    @ValueMapValue
    private boolean titleFromPage;
    
    @ValueMapValue
    private String cardTitle;
    

    這些變數可用來實作Card.java介面的其他方法。

  7. 實作Card.java介面中定義的其他方法:

    code language-java
    @Override
    public String getCtaLinkURL() {
        if(cardPage != null) {
            return cardPage.getPath() + ".html";
        }
        return null;
    }
    
    @Override
    public String getCtaText() {
        return ctaText;
    }
    
    @Override
    public Calendar getCardLastModified() {
       if(cardPage != null) {
           return cardPage.getLastModified();
       }
       return null;
    }
    
    @Override
    public String getCardTitle() {
        if(titleFromPage) {
            return cardPage != null ? cardPage.getTitle() : null;
        }
        return cardTitle;
    }
    
    note note
    NOTE
    您可以在🔗檢視完成的CardImpl.java。
  8. 開啟終端機視窗,並使用core目錄中的Maven autoInstallBundle設定檔僅部署core模組的更新。

    code language-shell
    $ cd core/
    $ mvn clean install -PautoInstallBundle
    

    如果使用AEM 6.x,請新增classic設定檔。

  9. 檢視JSON模型回應: http://localhost:4502/content/wknd-spa-angular/us/en.model.json並搜尋wknd-spa-angular/components/card

    code language-json
    "card": {
        "ctaText": "Read More",
        "cardTitle": "Page 1",
        "title": "Woman chillaxing with river views in Australian bushland",
        "src": "/content/wknd-spa-angular/us/en/home/_jcr_content/root/responsivegrid/card.coreimg.jpeg/1595190732886/adobestock-216674449.jpeg",
        "alt": "Female sitting on a large rock relaxing in afternoon dappled light the Australian bushland with views over the river",
        "cardLastModified": 1591360492414,
        "ctaLinkURL": "/content/wknd-spa-angular/us/en/home/page-1.html",
        ":type": "wknd-spa-angular/components/card"
    }
    

    請注意,更新CardImpl Sling模型中的方法後,JSON模型已更新為其他索引鍵/值組。

更新Angular元件

現在JSON模型已填入ctaLinkURLctaTextcardTitlecardLastModified的新屬性,我們可以更新Angular元件以顯示這些屬性。

  1. 返回IDE並開啟ui.frontend模組。 您可以選擇從新的終端機視窗啟動webpack開發伺服器,即時檢視變更:

    code language-shell
    $ cd ui.frontend
    $ npm install
    $ npm start
    
  2. ui.frontend/src/app/components/card/card.component.ts開啟card.component.ts。 新增其他@Input註解以擷取新模型:

    code language-diff
    export class CardComponent implements OnInit {
    
         @Input() src: string;
         @Input() alt: string;
         @Input() title: string;
    +    @Input() cardTitle: string;
    +    @Input() cardLastModified: number;
    +    @Input() ctaLinkURL: string;
    +    @Input() ctaText: string;
    
  3. 新增方法以檢查呼叫動作是否準備就緒,並根據cardLastModified輸入傳回日期/時間字串:

    code language-js
    export class CardComponent implements OnInit {
        ...
        get hasCTA(): boolean {
            return this.ctaLinkURL && this.ctaLinkURL.trim().length > 0 && this.ctaText && this.ctaText.trim().length > 0;
        }
    
        get lastModifiedDate(): string {
            const lastModifiedDate = this.cardLastModified ? new Date(this.cardLastModified) : null;
    
            if (lastModifiedDate) {
            return lastModifiedDate.toLocaleDateString();
            }
            return null;
        }
        ...
    }
    
  4. 開啟card.component.html並新增下列標籤以顯示標題、行動號召和上次修改日期:

    code language-html
    <div class="card"  *ngIf="hasContent">
        <app-image class="card__image" [src]="src" [alt]="alt" [title]="title"></app-image>
        <div class="card__content">
            <h2 class="card__title">
                {{cardTitle}}
                <span class="card__lastmod" *ngIf="lastModifiedDate">{{lastModifiedDate}}</span>
            </h2>
            <div class="card__action-container" *ngIf="hasCTA">
                <a [routerLink]="ctaLinkURL" class="card__action-link" [title]="ctaText">
                    {{ctaText}}
                </a>
            </div>
        </div>
    </div>
    

    已在card.component.scss新增Sass規則,以設定標題、行動號召和上次修改日期的樣式。

    note note
    NOTE
    您可以在此檢視已完成的Angular卡元件程式碼
  5. 使用Maven從專案的根將完整變更部署到AEM:

    code language-shell
    $ cd aem-guides-wknd-spa
    $ mvn clean install -PautoInstallSinglePackage
    
  6. 導覽至http://localhost:4502/editor.html/content/wknd-spa-angular/us/en/home.html檢視更新的元件:

    已在AEM中更新卡片元件

  7. 您應該能夠重新編寫現有內容以建立類似下列的頁面:

    卡片元件的最終製作

恭喜! congratulations

恭喜,您已瞭解如何擴充AEM元件,以及Sling模型和對話方塊如何搭配JSON模型使用。

您一律可以在GitHub上檢視完成的程式碼,或切換至分支Angular/extend-component-solution在本機簽出程式碼。

recommendation-more-help
e25b6834-e87f-4ff3-ba56-4cd16cdfdec4