扩展核心组件

了解如何扩展要与AEM SPA编辑器一起使用的现有核心组件。 了解如何扩展现有组件是一项功能强大的技术,可用于自定义和扩展AEM SPA Editor实施的功能。

目标

  1. 扩展现有的核心组件以包含其他属性和内容。
  2. 了解使用sling:resourceSuperType的组件继承的基本内容。
  3. 了解如何利用委派模式 for Sling模型来重复使用现有逻辑和功能。

将构建的内容

在本章中,将创建新的Card组件。 Card组件将扩展图像核心组件,添加其他内容字段,如标题和行动动员按钮,以对SPA中的其他内容执行Teaser角色。

卡片组件的最终创作

注意

在实际实施中,更合适的做法是简单地使用Teaser组件,然后扩展图像核心组件,以根据项目要求制作Card组件。 始终建议尽可能直接使用核心组件

前提条件

查看设置本地开发环境所需的工具和说明。

获取代码

  1. 通过Git下载本教程的起点:

    $ 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实例:

    $ mvn clean install -PautoInstallSinglePackage
    

    如果使用AEM 6.x添加classic配置文件:

    $ mvn clean install -PautoInstallSinglePackage -Pclassic
    
  3. 为传统WKND引用站点安装完成的包。 WKND引用站点提供的图像将在WKND SPA上重新使用。 可以使用AEM Package Manager安装包。

    包管理器安装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定义开始

    <?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. Inspect文件ui.apps/src/main/content/jcr_root/apps/wknd-spa-angular/components/image/.content.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组件最终会继承核心组件图像的功能。

    许多开发团队都努力成为DRY(不要重复自己)。 Sling继承使AEM能够实现此目的。

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

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

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

  5. card文件夹下,打开文件_cq_editConfig.xml。 此文件指示了AEM创作UI中的拖放行为。 扩展图像组件时,资源类型必须与组件本身匹配,这一点很重要。 查看<parameters>节点:

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

    大多数组件不需要cq:editConfig,但图像组件的图像和子代是例外。

  6. 在到ui.frontend模块的IDE交换机中,导航到ui.frontend/src/app/components/card:

    Angular组件开始

  7. Inspect文件card.component.ts

    该组件已被剪切为使用标准MapTo函数映射到AEM Card组件。

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

    查看类中srcalttitle的三个@Input参数。 这些是AEM组件中将映射到Angular组件的预期JSON值。

  8. 打开文件card.component.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的本地实例(如果尚未部署):

    $ 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组件对话框,并注意到添加了​Text​选项卡。

  5. 在​Text​选项卡中输入以下值:

    文本组件选项卡

    卡片路径 — 在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组件,我们需要更新Sling模型,该模型将填充Card组件的JSON。 我们还有机会实施两个业务逻辑:

  • 如果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. 在界面中添加以下方法:

    @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. 请遵循以下行:

    @Self
    @Via(type = ResourceSuperType.class)
    private Image image;
    

    上述注释将根据Card组件的sling:resourceSuperType继承实例化名为image的图像对象。

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

    然后,只需使用image对象来实现由Image接口定义的方法,而无需自己编写逻辑。 此技术用于getSrc()getAlt()getTitle()

  5. 接下来,实施initModel()方法以根据cardPath的值启动专用变量cardPage

    @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注释用于自动执行映射。

    @ValueMapValue
    private String cardPath;
    
    @ValueMapValue
    private String ctaText;
    
    @ValueMapValue
    private boolean titleFromPage;
    
    @ValueMapValue
    private String cardTitle;
    

    这些变量将用于为Card.java接口实施其他方法。

  7. 实施在Card.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;
    }
    
    注意

    您可以在此处🔗查看已完成的CardImpl.java。

  8. 打开终端窗口,并使用core目录中的Maven autoInstallBundle配置文件仅部署对core模块的更新。

    $ 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:

    "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开发服务器,以实时查看更改:

    $ cd ui.frontend
    $ npm install
    $ npm start
    
  2. ui.frontend/src/app/components/card/card.component.ts处打开card.component.ts。 添加附加的@Input注释以捕获新模型:

    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输入返回日期/时间字符串:

    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并添加以下标记以显示标题、行动动员和上次修改日期:

    <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规则以设置标题样式、操作调用和上次修改日期。

    注意

    您可以在此处🔗查看已完成的Angular卡组件代码。

  5. 使用Maven从项目的根部署对AEM的完整更改:

    $ 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. 您应该能够重新创作现有内容,以创建类似于以下内容的页面:

    卡片组件的最终创作

恭喜!

恭喜,您学习了如何使用扩展AEM组件,以及Sling模型和对话框如何与JSON模型一起使用。

您始终可以在GitHub上查看完成的代码,或通过切换到分支Angular/extend-component-solution在本地签出代码。

在此页面上