使用AEM SPA编辑器进行开发 — Hello World教程

警告

本教程为​已弃用。 建议遵循以下任一操作:AEM SPA Editor和Angular入门AEM SPA Editor和React快速入门

AEM SPA Editor支持对单页应用程序或SPA进行上下文内编辑。 本教程将介绍如何与SPA Editor JS SDK一起使用AEM SPA开发。 本教程将通过添加自定义Hello World组件来扩展We.Retail Journal应用程序。 用户可以使用React或Angular框架完成教程。

注意

单页应用程序(SPA)编辑器功能需要AEM 6.4 Service Pack 2或更高版本。

对于需要基于SPA框架的客户端渲染(例如,React或Angular)的项目,推荐使用SPA编辑器解决方案。

先决条件读取

本教程旨在重点介绍将SPA组件映射到AEM组件以启用上下文内编辑所需的步骤。 启动本教程的用户应该熟悉Adobe Experience Manager、AEM以及使用Angular框架的React进行开发的基本概念。 本教程涵盖后端和前端开发任务。

建议在开始本教程之前先审核以下资源:

本地开发环境

本教程旨在:

Adobe Experience Manager 6.5Adobe Experience Manager 6.4 + Service Pack 5

在本教程中,应安装以下技术和工具:

  1. Java 11
  2. Apache Maven - 3.3.1+
  3. Node.js - 8.11.1+ 和npm 5.6.0+(npm随node.js一起安装)

通过打开新终端并运行以下命令,再次检查上述工具的安装:

$ java -version
java version "11 +"

$ mvn -version
Apache Maven 3.3.9

$ node --version
v8.11.1

$ npm --version
6.1.0

概述

基本概念是将SPA组件映射到AEM组件。 AEM组件(运行服务器端)以JSON格式导出内容。 SPA会使用JSON内容,并在浏览器中运行客户端。 将创建SPA组件与AEM组件之间的1:1映射。

SPA组件映射

开箱即用地支持常用框架React JSAngular。 用户可以在Angular或React中完成本教程,无论这两个框架是他们最熟悉的。

项目设置

SPA开发只涉及AEM开发,而涉及到其他方面。 其目标是允许SPA开发独立进行,并且(大多)与AEM无关。

  • SPA项目在前端开发过程中可以独立于AEM项目运行。
  • 前端构建工具和技术(如Webpack、NPM、Grunt和Gulp)将继续使用。
  • 要为AEM构建,将编译SPA项目并自动将其包含在AEM项目中。
  • 用于将SPA部署到AEM的标准AEM包。

工件和部署概述

SPA开发只涉及AEM开发,而涉及到其他方面 — 允许SPA开发独立进行,并且(大多)与AEM无关。

本教程的目标是使用新组件扩展We.Retail Journal应用程序。 首先,下载We.Retail Journal应用程序的源代码,并将其部署到本地AEM。

  1. ​从GitHub下 载最新的We.Retail日志代码

    或从命令行中克隆存储库:

    $ git clone git@github.com:adobe/aem-sample-we-retail-journal.git
    
    注意

    本教程将针对包含项目​1.2.1-SNAPSHOT​版本的​主控​分支进行操作。

  2. 以下结构应该可见:

    项目文件夹结构

    项目包含以下Maven模块:

    • all:将整个项目嵌入并安装到单个包中。
    • bundles:包含两个OSGi包:包含和其他Java代码 Sling Models 的公用和核心。
    • ui.apps:包含项目的/apps部分,即JS和CSS客户端库、组件、特定于运行模式的配置。
    • ui.content:包含结构内容和配置(/content/conf)
    • react-app:We.Retail Journal React应用程序。这既是Maven模块,也是Webpack项目。
    • angular-app:We.Retail JournalAngular应用程序。这既是Maven模块,也是Webpack项目。
  3. 打开新的终端窗口并运行以下命令来构建整个应用程序并将其部署到运行在http://localhost:4502上的本地AEM实例。

    $ cd <src>/aem-sample-we-retail-journal
    $ mvn -PautoInstallSinglePackage clean install
    
    注意

    在此项目中,用于构建和打包整个项目的Maven配置文件是autoInstallSinglePackage

    注意

    如果在生成过程中收到错误,请确保Maven settings.xml文件包含Adobe的Maven对象存储库

  4. 导航至:

    We.Retail Journal应用程序应显示在AEM Sites编辑器中。

  5. 在编辑模式下,选择要编辑的组件并对内容进行更新。

    编辑组件

  6. 选择页面属性图标以打开页面属性。 选择编辑模板以打开页面的模板。

    页面属性菜单

  7. 在最新版本的SPA Editor中,可编辑的模板🔗的使用方式与传统Sites实施相同。 稍后将使用我们的自定义组件重新查看此内容。

    注意

    只有AEM 6.5和AEM 6.4 + Service Pack 5​支持可编辑的模板。

开发概述

概述开发

SPA开发迭代次数与AEM无关。 当SPA准备好部署到AEM中时,将执行以下高级步骤(如上图所示)。

  1. 将调用AEM项目内部版本,这反过来会触发SPA项目的内部版本。 We.Retail Journal使用​frontend-maven-plugin
  2. SPA项目的​aem-clientlib-generator将编译的SPA作为AEM客户端库嵌入到AEM项目中。
  3. AEM项目会生成一个AEM包,包括已编译的SPA,以及任何其他支持AEM代码。

创建AEM组件

角色:AEM开发人员

将首先创建AEM组件。 AEM组件负责呈现React组件读取的JSON属性。 AEM组件还负责为组件的任何可编辑属性提供一个对话框。

使用Eclipse或其他IDE导入We.Retail Journal Maven项目。

  1. 更新反应器​pom.xml​以删除Apache Rat插件。 此插件会检查每个文件,以确保存在许可证标头。 出于我们的目的,我们无需关注此功能。

    在​aem-sample-we-retail-journal/pom.xml​中,删除​apache-rate-plugin:

    <!-- Remove apache-rat-plugin -->
    <plugin>
            <groupId>org.apache.rat</groupId>
            <artifactId>apache-rat-plugin</artifactId>
            <configuration>
                <excludes combine.children="append">
                    <exclude>*</exclude>
                        ...
                </excludes>
            </configuration>
            <executions>
                    <execution>
                        <phase>verify</phase>
                        <goals>
                            <goal>check</goal>
                        </goals>
                </execution>
            </executions>
        </plugin>
    
  2. 在​we-retail-journal-content(<src>/aem-sample-we-retail-journal/ui.apps)模块中,在ui.apps/jcr_root/apps/we-retail-journal/components下方创建一个名为​helloworld​的类型为​cq:Component​的新节点。

  3. 将以下属性添加到​helloworld​组件中,该组件以下XML(/helloworld/.content.xml)表示:

    <?xml version="1.0" encoding="UTF-8"?>
    <jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
        jcr:description="Hello World Component for We.Retail Journal"
        jcr:primaryType="cq:Component"
        jcr:title="Hello World"
        componentGroup="We.Retail Journal" />
    

    Hello World组件

    注意

    为了说明可编辑的模板功能,我们有意设置了componentGroup="Custom Components"。 在真实项目中,最好尽量减少组件组的数量,这样一个更好的组就是“We.Retail Journal”,以匹配其他内容组件。

    只有AEM 6.5和AEM 6.4 + Service Pack 5​支持可编辑的模板。

  4. 接下来将创建一个对话框,以允许为​Hello World​组件配置自定义消息。 在/apps/we-retail-journal/components/helloworld下添加节点名称​cq:dialog,共​nt:unstructured

  5. cq:dialog​将显示一个文本字段,该字段将文本保留到名为​message​的属性。 在新创建的​cq:dialog​下,添加以下节点和属性,如下面的XML(helloworld/_cq_dialog/.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" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
        jcr:primaryType="nt:unstructured"
        jcr:title="We.Retail Journal - Hello World"
        sling:resourceType="cq/gui/components/authoring/dialog">
        <content
            jcr:primaryType="nt:unstructured"
            sling:resourceType="granite/ui/components/coral/foundation/container">
            <items jcr:primaryType="nt:unstructured">
                <tabs
                    jcr:primaryType="nt:unstructured"
                    sling:resourceType="granite/ui/components/coral/foundation/tabs"
                    maximized="{Boolean}true">
                    <items jcr:primaryType="nt:unstructured">
                        <properties
                            jcr:primaryType="nt:unstructured"
                            jcr:title="Properties"
                            sling:resourceType="granite/ui/components/coral/foundation/container"
                            margin="{Boolean}true">
                            <items jcr:primaryType="nt:unstructured">
                                <columns
                                    jcr:primaryType="nt:unstructured"
                                    sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"
                                    margin="{Boolean}true">
                                    <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"
                                                    fieldLabel="Message"
                                                    name="./message"
                                                    required="{Boolean}true"/>
                                            </items>
                                        </column>
                                    </items>
                                </columns>
                            </items>
                        </properties>
                    </items>
                </tabs>
            </items>
        </content>
    </jcr:root>
    

    文件结构

    上述XML节点定义将创建一个对话框,其中包含一个文本字段,用户可以输入“消息”。 请注意<message />节点中的属性name="./message"。 此名称是将存储在AEM JCR中的属性的名称。

  6. 接下来将创建空策略对话框(cq:design_dialog)。 需要使用策略对话框才能在模板编辑器中查看组件。 对于此简单用例,它将是一个空对话框。

    /apps/we-retail-journal/components/helloworld下添加nt:unstructured的节点名称cq:design_dialog

    配置以下XML形式表示(helloworld/_cq_design_dialog/.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" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
    jcr:primaryType="nt:unstructured" />
    
  7. 从命令行将代码库部署到AEM:

    $ cd <src>/aem-sample-we-retail-journal/content
    $ mvn -PautoInstallPackage clean install
    

    CRXDE Lite中,通过检查/apps/we-retail-journal/components:下的文件夹来验证组件是否已部署

    部署的组件结构CRXDE Lite

创建Sling模型

角色:AEM开发人员

接下来将创建Sling Model以支持Hello World组件。 在传统WCM用例中, Sling Model实施任何业务逻辑,服务器端渲染脚本(HTL)将调用Sling Model。 这样可使渲染脚本变得相对简单。

Sling Models 在SPA用例中,还会使用来实施服务器端业务逻辑。区别在于,在SPA用例中,Sling Models会将其方法公开为序列化JSON。

注意

作为最佳实践,开发人员应尽可能使用AEM核心组件。 核心组件提供的JSON输出“SPA就绪”,具有其他功能,其中Sling Models提供了一些JSON输出,使开发人员能够将更多精力放在前端演示上。

  1. 在您选择的编辑器中,打开​we-retail-journal-commons​项目(<src>/aem-sample-we-retail-journal/bundles/commons)。

  2. 在包com.adobe.cq.sample.spa.commons.impl.models中:

    • 创建一个名为HelloWorld的新类。
    • com.adobe.cq.export.json.ComponentExporter.添加实现接口

    新建Java类向导

    必须实施ComponentExporter接口,才能使Sling Model与AEM Content Services兼容。

     package com.adobe.cq.sample.spa.commons.impl.models;
    
     import com.adobe.cq.export.json.ComponentExporter;
    
     public class HelloWorld implements ComponentExporter {
    
         @Override
         public String getExportedType() {
             return null;
         }
     }
    
  3. 添加名为RESOURCE_TYPE的静态变量以标识HelloWorld组件的资源类型:

     ...
     public class HelloWorld implements ComponentExporter {
    
         static final String RESOURCE_TYPE = "we-retail-journal/components/helloworld";
    
         ...
     }
    
  4. @Model@Exporter添加OSGi注释。 @Model注释将类注册为Sling Model。 @Exporter注释将使用Jackson Exporter框架以序列化JSON形式显示这些方法。

    import org.apache.sling.api.SlingHttpServletRequest;
    import org.apache.sling.models.annotations.Exporter;
    import org.apache.sling.models.annotations.Model;
    import com.adobe.cq.export.json.ExporterConstants;
    ...
    
    @Model(
            adaptables = SlingHttpServletRequest.class,
            adapters = {ComponentExporter.class},
            resourceType = HelloWorld.RESOURCE_TYPE
    )
    @Exporter(
            name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, 
            extensions = ExporterConstants.SLING_MODEL_EXTENSION
    )
    public class HelloWorld implements ComponentExporter {
    
    ...
    
  5. 实施方法getDisplayMessage()以返回JCR属性message。 使用@ValueMapValue的Sling Model注释,可轻松检索存储在组件下方的属性message@Optional注释很重要,因为首次将组件添加到页面时,将不会填充message

    作为业务逻辑的一部分,字符串“Hello”将附加到消息的前面。

    import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
    import org.apache.sling.models.annotations.Optional;
    
    ...
    
    public class HelloWorld implements ComponentExporter {
    
       static final String RESOURCE_TYPE = "we-retail-journal/components/helloworld";
    
       private static final String PREPEND_MSG = "Hello";
    
        @ValueMapValue @Optional
        private String message;
    
        public String getDisplayMessage() {
            if(message != null && message.length() > 0) {
                return PREPEND_MSG + " "  + message;
            }
            return null;
        }
    
    ...
    
    注意

    方法名称getDisplayMessage很重要。 使用Jackson Exporter序列化Sling Model后,它将作为JSON属性显示:displayMessage。 Jackson Exporter将序列化并公开所有不采用参数的getter方法(除非明确标记为忽略)。 稍后在React /Angular应用程序中,我们将读取此属性值并将其显示为应用程序的一部分。

    方法getExportedType也很重要。 组件resourceType的值将用于将JSON数据“映射”到前端组件(Angular/React)。 我们将在下一节中探讨此内容。

  6. 实施方法getExportedType()以返回HelloWorld组件的资源类型。

     @Override
        public String getExportedType() {
            return RESOURCE_TYPE;
        }
    

    可在此处找到​HelloWorld.java​的完整代码。

  7. 使用Apache Maven将代码部署到AEM:

    $ cd <src>/sample-we-retail-spa-content/bundles/commons
    $ mvn -PautoInstallPackage clean install
    

    在OSGi控制台中,导航到Status > Sling模型,以验证Sling Model的部署和注册。

    您应会看到HelloWorld Sling模型已绑定到we-retail-journal/components/helloworld Sling资源类型,并且已将其注册为Sling Model Exporter Servlet:

    com.adobe.cq.sample.spa.commons.impl.models.HelloWorld - we-retail-journal/components/helloworld
    com.adobe.cq.sample.spa.commons.impl.models.HelloWorld exports 'we-retail-journal/components/helloworld' with selector 'model' and extension '[Ljava.lang.String;@6480f3e5' with exporter 'jackson'
    

创建React组件

角色:前端开发人员

接下来,将创建React组件。 使用您选择的编辑器打开​react-app​模块(<src>/aem-sample-we-retail-journal/react-app)。

注意

如果您只对Angular开发感兴趣,请跳过此部分。

  1. react-app文件夹内,导航到其src文件夹。 展开组件文件夹可查看现有的React组件文件。

    react component file structure

  2. 在名为HelloWorld.js的components文件夹下添加新文件。

  3. 打开 HelloWorld.js. 添加import语句以导入React组件库。 添加第二个import语句以导入由Adobe提供的MapTo帮助程序。 MapTo帮助程序提供React组件到AEM组件JSON的映射。

    import React, {Component} from 'react';
    import {MapTo} from '@adobe/cq-react-editable-components';
    
  4. 在import语句下方,创建一个名为HelloWorld的新类,该类用于扩展React Component接口。 将所需的render()方法添加到HelloWorld类中。

    import React, {Component} from 'react';
    import {MapTo} from '@adobe/cq-react-editable-components';
    
    class HelloWorld extends Component {
    
        render() {
    
        }
    }
    
  5. MapTo帮助程序自动将名为cqModel的对象包含在React组件的prop中。 cqModel包含Sling Model公开的所有属性。

    请记住之前创建的Sling Model包含方法getDisplayMessage()getDisplayMessage() 在输出时将转换为名为 displayMessage 的JSON键。

    实施render()方法以输出包含displayMessage值的h1标记。 JSX(JavaScript的语法扩展)用于返回组件的最终标记。

    ...
    
    class HelloWorld extends Component {
        render() {
    
            if(this.props.displayMessage) {
                return (
                    <div className="cmp-helloworld">
                        <h1 className="cmp-helloworld_message">{this.props.displayMessage}</h1>
                    </div>
                );
            }
            return null;
        }
    }
    
  6. 实施编辑配置方法。 此方法通过MapTo帮助程序进行传递,并为AEM编辑器提供在组件为空时显示占位符的信息。 在将组件添加到SPA但尚未创作时,会发生这种情况。 在HelloWorld类下添加以下内容:

    ...
    
    class HelloWorld extends Component {
        ...
    }
    
    const HelloWorldEditConfig = {
    
        emptyLabel: 'Hello World',
    
        isEmpty: function(props) {
            return !props || !props.displayMessage || props.displayMessage.trim().length < 1;
        }
    };
    
    ...
    
  7. 在文件末尾,调用MapTo帮助程序,并传递HelloWorld类和HelloWorldEditConfig。 这将根据AEM组件的资源类型将React组件映射到React组件:we-retail-journal/components/helloworld

    MapTo('we-retail-journal/components/helloworld')(HelloWorld, HelloWorldEditConfig);
    

    可在此处找到​HelloWorld.js​的已完成代码。

  8. 打开文件ImportComponents.js。 可在<src>/aem-sample-we-retail-journal/react-app/src/ImportComponents.js找到。

    添加一行,以要求在编译的JavaScript包中使用包含其他组件的HelloWorld.js:

    ...
      require('./components/Text');
      require('./components/Image');
      require('./components/HelloWorld');
    ...
    
  9. components文件夹中,创建一个名为HelloWorld.css的新文件,作为HelloWorld.js.的同级文件。使用以下内容填充该文件,为HelloWorld组件创建一些基本样式:

    /* HelloWorld.css to style HelloWorld component */
    
    .cmp-helloworld_message {
        text-align: center;
        color: #ff505e;
        text-transform: unset;
        letter-spacing: unset;
    }
    
  10. 重新打开HelloWorld.js并在import语句下方更新,以要求HelloWorld.css:

    import React, {Component} from 'react';
    import {MapTo} from '@adobe/cq-react-editable-components';
    
    require('./HelloWorld.css');
    
    ...
    
  11. 使用Apache Maven将代码部署到AEM:

    $ cd <src>/sample-we-retail-spa-content
    $ mvn -PautoInstallSinglePackage clean install
    
  12. CRXDE-Lite中,打开/apps/we-retail-journal/react/clientlibs/we-retail-journal-react/js/app.js。 在app.js中快速搜索HelloWorld,以验证React组件是否已包含在编译的应用程序中。

    注意

    app.js 捆绑的React应用程序。该代码不再为人类可读。 npm run build命令已触发优化内部版本,该内部版本可输出可供现代浏览器解释的编译的JavaScript。

创建Angular组件

角色:前端开发人员

注意

如果您只对React开发感兴趣,请跳过此部分。

接下来,将创建Angular组件。 使用您选择的编辑器打开​angular应用程序​模块(<src>/aem-sample-we-retail-journal/angular-app)。

  1. angular-app文件夹内,导航到其src文件夹。 展开组件文件夹可查看现有的Angular组件文件。

    Angular文件结构

  2. 在名为helloworld的组件文件夹下添加一个新文件夹。 在helloworld文件夹下,添加名为helloworld.component.css, helloworld.component.html, helloworld.component.ts的新文件。

    /angular-app
        /src
            /app
                /components
    +                /helloworld
    +                    helloworld.component.css
    +                    helloworld.component.html
    +                    helloworld.component.ts
    
  3. 打开 helloworld.component.ts. 添加import语句以导入AngularComponentInput类。 创建新组件,将styleUrlstemplateUrl指向helloworld.component.csshelloworld.component.html。 最后,导出类HelloWorldComponent,预期输入为displayMessage

    //helloworld.component.ts
    
    import { Component, Input } from '@angular/core';
    
    @Component({
      selector: 'app-helloworld',
      host: { 'class': 'cmp-helloworld' },
      styleUrls:['./helloworld.component.css'],
      templateUrl: './helloworld.component.html',
    })
    
    export class HelloWorldComponent {
      @Input() displayMessage: string;
    }
    
    注意

    如果回想一下之前创建的Sling Model,会发现一个方法​getDisplayMessage()。 此方法的序列化JSON将为​displayMessage,我们现在在Angular应用程序中读取它。

  4. 打开helloworld.component.html以包含将打印displayMessage属性的h1标记:

    <h1 *ngIf="displayMessage" class="cmp-helloworld_message">
        {{displayMessage}}
    </h1>
    
  5. 更新helloworld.component.css以包含组件的一些基本样式。

    :host-context {
        display: block;
    };
    
    .cmp-helloworld {
        display:block;
    }
    .cmp-helloworld_message {
        text-align: center;
        color: #ff505e;
        text-transform: unset;
        letter-spacing: unset;
    }
    
  6. 使用以下测试台更新helloworld.component.spec.ts:

    import { async, ComponentFixture, TestBed } from '@angular/core/testing';
    
    import { HelloWorldComponent } from './helloworld.component';
    
        describe('HelloWorld', () => {
        let component: HelloWorldComponent;
        let fixture: ComponentFixture<HelloWorldComponent>;
    
        beforeEach(async(() => {
            TestBed.configureTestingModule({
            declarations: [ HelloWorldComponent ]
            })
            .compileComponents();
        }));
    
        beforeEach(() => {
            fixture = TestBed.createComponent(HelloWorldComponent);
            component = fixture.componentInstance;
            fixture.detectChanges();
        });
    
        it('should create', () => {
            expect(component).toBeTruthy();
        });
    });
    
  7. 下次更新src/components/mapping.ts以包含HelloWorldComponent。 添加HelloWorldEditConfig,该将在配置组件之前在AEM编辑器中标记占位符。 最后,添加一行,以使用MapTo帮助程序将AEM组件映射到Angular组件。

    // src/components/mapping.ts
    
    import { HelloWorldComponent } from "./helloworld/helloworld.component";
    
    ...
    
    const HelloWorldEditConfig = {
    
        emptyLabel: 'Hello World',
    
        isEmpty: function(props) {
            return !props || !props.displayMessage || props.displayMessage.trim().length < 1;
        }
    };
    
    ...
    
    MapTo('we-retail-journal/components/helloworld')(HelloWorldComponent, HelloWorldEditConfig);
    

    可在此处找到​mapping.ts​的完整代码。

  8. 更新src/app.module.ts以更新​NgModule。 将​HelloWorldComponent​添加为​声明,它属于​AppModule。 另外,将HelloWorldComponent添加为​entryComponent,以便在处理JSON模型时对其进行编译并动态包含在应用程序中。

    import { HelloWorldComponent } from './components/helloworld/helloworld.component';
    
    ...
    
    @NgModule({
      imports: [BrowserModule.withServerTransition({ appId: 'we-retail-sample-angular' }),
        SpaAngularEditableComponentsModule,
      AngularWeatherWidgetModule.forRoot({
        key: "37375c33ca925949d7ba331e52da661a",
        name: WeatherApiName.OPEN_WEATHER_MAP,
        baseUrl: 'http://api.openweathermap.org/data/2.5'
      }),
        AppRoutingModule,
        BrowserTransferStateModule],
      providers: [ModelManagerService,
        { provide: APP_BASE_HREF, useValue: '/' }],
      declarations: [AppComponent,
        TextComponent,
        ImageComponent,
        WeatherComponent,
        NavigationComponent,
        MenuComponent,
        MainContentComponent,
        HelloWorldComponent],
      entryComponents: [TextComponent,
        ImageComponent,
        WeatherComponent,
        NavigationComponent,
        MainContentComponent,
        HelloWorldComponent],
      bootstrap: [AppComponent]
     })
    

    可在此处找到​app.module.ts​的已完成代码。

  9. 使用Maven将代码部署到AEM:

    $ cd <src>/sample-we-retail-spa-content
    $ mvn -PautoInstallSinglePackage clean install
    
  10. CRXDE-Lite中,打开/apps/we-retail-journal/angular/clientlibs/we-retail-journal-angular/js/main.js。 在main.js中对​HelloWorld​执行快速搜索,以验证是否包含Angular组件。

    注意

    main.js 捆绑的Angular应用程序。该代码不再为人类可读。 npm run build命令已触发优化内部版本,该内部版本可输出可供现代浏览器解释的编译的JavaScript。

更新模板

  1. 导航到React和/或Angular版本的可编辑模板:

  2. 选择主布局容器,然后选择策略图标以打开其策略:

    选择布局策略

    在​属性 > 允许的组件​下,搜索​Custom Components。 您应会看到​Hello World​组件,请选择它。 单击右上角的复选框以保存更改。

    布局容器策略配置

  3. 保存后,您应会在布局容器中看到​HelloWorld​组件是允许的组件。

    允许的组件已更新

    注意

    只有AEM 6.5和AEM 6.4.5支持SPA编辑器的可编辑模板功能。 如果使用AEM 6.4,则需要通过CRXDE Lite手动配置允许的组件的策略:/conf/we-retail-journal/react/settings/wcm/policies/wcm/foundation/components/responsivegrid/default/conf/we-retail-journal/angular/settings/wcm/policies/wcm/foundation/components/responsivegrid/default

    CRXDE Lite显示布局容器中允许的组件的更新策略配置:

    CRXDE Lite显示布局容器中允许的组件的更新策略配置

把它们整合起来

  1. 导航到Angular或React页面:

  2. 找到​Hello World​组件,然后将​Hello World​组件拖放到页面上。

    hello world drag + drop

    应会显示占位符。

    《你好世界保镖》

  3. 选择组件并在对话框中添加消息,即“World”或“Your Name”。 保存更改。

    呈现的组件

    请注意,字符串“Hello”始终附加到消息的前面。 这是HelloWorld.java Sling Model中逻辑的结果。

后续步骤

HelloWorld组件的完成解决方案

疑难解答

无法在Eclipse中构建项目

错误: 将项目导入Eclipse以执行 We.Retail Journal 无法识别的目标时出错:

Execution npm install, Execution npm run build, Execution default-analyze-classes*

eclipse错误向导

解决办法:单击“完成”以稍后解决这些问题。这不应妨碍教程的完成。

错误:在Maven生成过 react-app程中, React模块无法成功生成。

解决办法: 尝试删除 node_modules react-app 下的文件夹。从项目的根中重新运行Apache Maven命令mvn clean install -PautoInstallSinglePackage

AEM中未满足的依赖项

包管理器依赖关系错误

如果不满足AEM依赖关系,则在​AEM包管理器​或​AEM Web Console(Felix Console)中,这表示SPA编辑器功能不可用。

组件未显示

错误:即使成功部署并验证编译的React/Angular应用程序版本是否具有更新的组 helloworld 件,当我将组件拖动到页面时,组件仍不显示。我可以在AEM UI中查看组件。

解决办法:清除浏览器的历史记录/缓存和/或打开新浏览器或使用隐身模式。如果这不起作用,则使本地AEM实例上的客户端库缓存失效。 AEM会尝试缓存大型clientlibraries以提高效率。 有时,需要手动使缓存失效来修复缓存过期代码的问题。

导航到:http://localhost:4502/libs/granite/ui/content/dumplibs.rebuild.html并单击无效缓存。 返回到您的React/Angular页面并刷新该页面。

重建客户端库

在此页面上