Extend a Core Component extend-component

IMPORTANT
SPA 编辑器已被新项目弃用。Adobe 对现有项目仍提供支持,但不应在新项目中使用。目前,AEM 中用于管理 Headless 内容的首选编辑器是:

Learn how to extend an existing Core Component to be used with the AEM SPA Editor. Understanding how to extend an existing component is a powerful technique to customize and expand the capabilities of an AEM SPA Editor implementation.

目标

  1. Extend an existing Core Component with additional properties and content.
  2. Understand the basic of Component Inheritance with the use of sling:resourceSuperType.
  3. Learn how to use the Delegation Pattern for Sling Models to reuse existing logic and functionality.

您将构建什么

在本章中,创建了一个新的Card组件。 Card组件扩展了图像核心组件,添加了其他内容字段(如“标题”和“Call to action”按钮)来为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 将代码签出到本地。

检查初始卡实施

章节起始代码提供了初始卡组件。 检查卡实施的起点。

  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图像组件的功能。

  3. 检查文件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图像组件继承了核心组件图像的功能。

    也称为代理模式 Sling资源继承是一种强大的设计模式,它允许子组件继承功能并在需要时扩展/覆盖行为。 Sling继承支持多个继承级别,因此最终,新Card组件会继承核心组件图像的功能。

    许多开发团队都努力做到自我(不要重复自己)。 通过Sling继承,可在AEM中实现这一点。

  4. card文件夹下,打开文件_cq_dialog/.content.xml

    此文件是Card组件的组件对话框定义。 如果使用Sling继承,则可以使用Sling资源合并器的功能覆盖或扩展对话框的各个部分。 在此示例中,向对话框添加了一个新选项卡,用于从作者捕获其他数据以填充卡组件。

    sling:orderBefore等属性允许开发人员选择插入新选项卡或表单字段的位置。 在这种情况下,Text选项卡插入到asset选项卡之前。 要充分利用Sling资源合并器,请务必了解图像组件对话框的原始对话框节点结构。

  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. 查看文件 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。 检查/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. 添加用于检查Call to action是否就绪以及根据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并添加以下标记以显示标题、call to action和上次修改日期:

    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规则以设置标题、call to action和上次修改日期的样式。

    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