将SPA组件映射到AEM组件 map-components
了解如何使用Angular SPA编辑器JS SDK将AEM组件映射到Adobe Experience Manager (AEM)组件。 组件映射使用户能够在AEM SPA编辑器中对SPA组件进行动态更新,类似于传统的AEM创作。
本章更深入地介绍了AEM JSON模型API,以及如何将由AEM组件公开的JSON内容作为prop自动插入到Angular组件中。
目标
- 了解如何将AEM组件映射到SPA组件。
- 了解 Container 组件与 Content 组件之间的区别。
- 创建映射到现有Angular组件的新AEM组件。
您将构建什么
本章将检查提供的Text SPA组件如何映射到AEM Text组件。 已创建新的Image SPA组件,该组件可在SPA中使用并在AEM中创作。 布局容器和 模板编辑器 策略的开箱即用功能还将用于创建外观变化稍大的视图。
先决条件
查看设置本地开发环境所需的工具和说明。
获取代码
-
通过Git下载本教程的起点:
code language-shell $ git clone git@github.com:adobe/aem-guides-wknd-spa.git $ cd aem-guides-wknd-spa $ git checkout Angular/map-components-start -
使用Maven将代码库部署到本地AEM实例:
code language-shell $ mvn clean install -PautoInstallSinglePackage如果使用AEM 6.x,请添加
classic配置文件:code language-shell $ mvn clean install -PautoInstallSinglePackage -Pclassic
您始终可以在GitHub上查看完成的代码,或通过切换到分支Angular/map-components-solution在本地签出代码。
映射方法
基本概念是将SPA组件映射到AEM组件。 AEM组件运行服务器端,将内容导出为JSON模型API的一部分。 SPA使用在浏览器中运行客户端的JSON内容。 创建了SPA组件与AEM组件之间的1:1映射。
将AEM组件映射到Angular组件的高级概述
检查文本组件
AEM项目原型提供了一个映射到AEM 文本组件的Text组件。 这是 content 组件的示例,该组件渲染来自AEM的content。
我们来看看组件的工作方式。
检查JSON模型
-
在介绍SPA代码之前,请务必了解AEM提供的JSON模型。 导航到核心组件库并查看文本组件的页面。 核心组件库提供了所有AEM核心组件的示例。
-
为以下示例之一选择 JSON 选项卡:
您应该看到三个属性:
text、richText和:type。:type是一个保留属性,它列出了AEM组件的sling:resourceType(或路径)。:type的值用于将AEM组件映射到SPA组件。text和richText是对SPA组件公开的其他属性。
检查文本组件
-
打开新终端并导航到项目中的
ui.frontend文件夹。 运行npm install,然后运行npm start以启动webpack开发服务器:code language-shell $ cd ui.frontend $ npm run start:mockui.frontend模块当前设置为使用模拟JSON模型。 -
您应会看到一个新的浏览器窗口打开http://localhost:4200/content/wknd-spa-angular/us/en/home.html
包含模拟内容的
-
在您选择的IDE中,打开WKND SPA的AEM项目。 展开
ui.frontend模块并打开ui.frontend/src/app/components/text/text.component.ts下的文件text.component.ts:
-
第一个要检查的区域是位于第35行的
class TextComponent:code language-js export class TextComponent { @Input() richText: boolean; @Input() text: string; @Input() itemName: string; @HostBinding('innerHtml') get content() { return this.richText ? this.sanitizer.bypassSecurityTrustHtml(this.text) : this.text; } @HostBinding('attr.data-rte-editelement') editAttribute = true; constructor(private sanitizer: DomSanitizer) {} }@Input()修饰符用于声明通过映射JSON对象设置的字段,该对象先前已查看。
@HostBinding('innerHtml') get content()是一种从this.text的值中公开所编写的文本内容的方法。 如果内容是富文本(由this.richText标志确定),将绕过Angular的内置安全性。 Angular的DomSanitizer用于“清理”原始HTML并防止跨站点脚本漏洞。 使用@HostBinding修饰器将方法绑定到innerHtml属性。 -
接下来,在~第24行检查
TextEditConfig:code language-js const TextEditConfig = { emptyLabel: 'Text', isEmpty: cqModel => !cqModel || !cqModel.text || cqModel.text.trim().length < 1 };上述代码负责确定何时在AEM创作环境中呈现占位符。 如果
isEmpty方法返回true,则会呈现占位符。 -
最后,查看第53行以下位置的
MapTo调用:code language-js MapTo('wknd-spa-angular/components/text')(TextComponent, TextEditConfig );MapTo is provided by the AEM SPA Editor JS SDK (
@adobe/cq-angular-editable-components). 路径wknd-spa-angular/components/text表示AEM组件的sling:resourceType。 此路径与之前观察到的JSON模型公开的:type匹配。 MapTo解析JSON模型响应并将正确的值传递给SPA组件的@Input()变量。您可以在
ui.apps/src/main/content/jcr_root/apps/wknd-spa-angular/components/text找到AEMText组件定义。 -
通过在
ui.frontend/src/mocks/json/en.model.json修改 en.model.json 文件来进行试验。在第62行~行更新第一个
Text值以使用H1和u标记:code language-json "text": { "text": "<h1><u>Hello World!</u></h1>", "richText": true, ":type": "wknd-spa-angular/components/text" }返回浏览器以查看 webpack开发服务器 提供的效果:
尝试在true / false之间切换
richText属性以查看正在运行的渲染逻辑。 -
在
ui.frontend/src/app/components/text/text.component.html处检查text.component.html。此文件为空,因为组件的全部内容由
innerHTML属性设置。 -
在
ui.frontend/src/app/app.module.ts处检查app.module.ts。code language-js @NgModule({ imports: [ BrowserModule, SpaAngularEditableComponentsModule, AppRoutingModule ], providers: [ModelManagerService, { provide: APP_BASE_HREF, useValue: '/' }], declarations: [AppComponent, TextComponent, PageComponent, HeaderComponent], entryComponents: [TextComponent, PageComponent], bootstrap: [AppComponent] }) export class AppModule {}未显式包含TextComponent,而是通过AEM SPA编辑器JS SDK提供的 AEMResponsiveGridComponent 动态包含。 因此,必须在app.module.ts' entryComponents数组中列出。
创建图像组件
接下来,创建映射到AEM 图像组件的ImageAngular组件。 Image组件是 content 组件的另一个示例。
检查JSON
在跳转到SPA代码之前,请检查AEM提供的JSON模型。
-
导航到核心组件库🔗中的图像示例。
src、alt和title的属性用于填充SPAImage组件。note note NOTE 其他公开的图像属性( lazyEnabled、widths)允许开发人员创建自适应和延迟加载组件。 The component built in this tutorial is simple and does not use these advanced properties. -
Return to your IDE and open up the
en.model.jsonatui.frontend/src/mocks/json/en.model.json. Since this is a net-new component for our project we need to "mock" the Image JSON.At ~line 70 add a JSON entry for the
imagemodel (don't forget about the trailing comma,after the secondtext_386303036) and update the:itemsOrderarray.code language-json ... ":items": { ... "text_386303036": { "text": "<p>A new text component.</p>\r\n", "richText": true, ":type": "wknd-spa-angular/components/text" }, "image": { "alt": "Rock Climber in New Zealand", "title": "Rock Climber in New Zealand", "src": "/mocks/images/adobestock-140634652.jpeg", ":type": "wknd-spa-angular/components/image" } }, ":itemsOrder": [ "text", "text_386303036", "image" ],The project includes a sample image at
/mock-content/adobestock-140634652.jpegthat is used with the webpack dev server.You can view the full en.model.json here.
-
Add a stock photo to be displayed by the component.
Create a new folder named images beneath
ui.frontend/src/mocks. Download adobestock-140634652.jpeg and place it in the newly created images folder. Feel free to use your own image, if desired.
Implement the Image component
-
Stop the webpack dev server if started.
-
Create a new Image component by running the Angular CLI
ng generate componentcommand from withinui.frontendfolder:code language-shell $ ng generate component components/image -
In the IDE, open image.component.ts at
ui.frontend/src/app/components/image/image.component.tsand update as follows:code language-js import {Component, Input, OnInit} from '@angular/core'; import {MapTo} from '@adobe/cq-angular-editable-components'; const ImageEditConfig = { emptyLabel: 'Image', isEmpty: cqModel => !cqModel || !cqModel.src || cqModel.src.trim().length < 1 }; @Component({ selector: 'app-image', templateUrl: './image.component.html', styleUrls: ['./image.component.scss'] }) export class ImageComponent implements OnInit { @Input() src: string; @Input() alt: string; @Input() title: string; constructor() { } get hasImage() { return this.src && this.src.trim().length > 0; } ngOnInit() { } } MapTo('wknd-spa-angular/components/image')(ImageComponent, ImageEditConfig);ImageEditConfigis the configuration to determine whether to render the author placeholder in AEM, based on if thesrcproperty is populated.@Input()ofsrc,alt, andtitleare the properties mapped from the JSON API.hasImage()is a method that will determine if the image should be rendered.MapTomaps the SPA component to the AEM component located atui.apps/src/main/content/jcr_root/apps/wknd-spa-angular/components/image. -
Open image.component.html and update it as follows:
code language-html <ng-container *ngIf="hasImage"> <img class="image" [src]="src" [alt]="alt" [title]="title"/> </ng-container>This will render the
<img>element ifhasImagereturns true. -
Open image.component.scss and update it as follows:
code language-scss :host-context { display: block; } .image { margin: 1rem 0; width: 100%; border: 0; }note note NOTE The :host-contextrule is critical for the AEM SPA editor placeholder to function correctly. All SPA components that are intended to be authored in the AEM page editor will need this rule at a minimum. -
Open
app.module.tsand add theImageComponentto theentryComponentsarray:code language-js entryComponents: [TextComponent, PageComponent, ImageComponent],Like the
TextComponent, theImageComponentis dynamically loaded, and must be included in theentryComponentsarray. -
启动 webpack开发服务器 以查看
ImageComponent渲染。code language-shell $ npm run start:mock
图像已添加到SPA
note note NOTE 附加质询:实施新方法以将 title的值显示为图像下方的标题。
在AEM中更新策略
ImageComponent组件仅在 webpack开发服务器 中可见。 接下来,将更新的SPA部署到AEM并更新模板策略。
-
停止webpack开发服务器,并从项目的 根 中,使用您的Maven技能将更改部署到AEM:
code language-shell $ cd aem-guides-wknd-spa $ mvn clean install -PautoInstallSinglePackage -
从AEM开始屏幕导航到工具 > 模板 > WKND SPA Angular。
选择并编辑SPA页面:
-
选择 布局容器 并单击它的 策略 图标以编辑策略:
-
在允许的组件 > WKND SPA Angular - Content >下,检查 Image 组件:
已选择
在默认组件 > 添加映射下,并选择 图像 — WKND SPA Angular - Content 组件:
输入
image/*的MIME类型。单击 完成 以保存策略更新。
-
在 布局容器 中,单击 文本 组件的 策略 图标:
创建名为 WKND SPA Text 的新策略。 在插件 > 格式 >下,选中所有框以启用其他格式选项:
在插件 > 段落样式 >下,选中 启用段落样式 的框:
单击 完成 以保存策略更新。
-
导航到主页 http://localhost:4502/editor.html/content/wknd-spa-angular/us/en/home.html。
您还应该能够编辑
Text组件并在 全屏 模式下添加其他段落样式。
-
您还应该能够从 资产查找器 中拖放图像:
-
通过AEM Assets添加您自己的映像,或者为标准WKND引用站点安装完成的代码库。 WKND引用站点包含可在WKND SPA上重复使用的许多图像。 可以使用AEM的包管理器安装该包。
检查布局容器
AEM SPA编辑器SDK自动提供对 布局容器 的支持。 名称指示的 布局容器 是 容器 组件。 容器组件是接受JSON结构的组件,该结构表示 其他 组件并动态实例化它们。
让我们进一步检查布局容器。
-
在IDE中,打开
ui.frontend/src/app/components/responsive-grid处的responsive-grid.component.ts:code language-js import { AEMResponsiveGridComponent,MapTo } from '@adobe/cq-angular-editable-components'; MapTo('wcm/foundation/components/responsivegrid')(AEMResponsiveGridComponent);AEMResponsiveGridComponent是作为AEM SPA Editor SDK的一部分实现的,并通过import-components包含在项目中。 -
在浏览器中导航到http://localhost:4502/content/wknd-spa-angular/us/en.model.json
布局容器组件具有
wcm/foundation/components/responsivegrid的sling:resourceType,SPA编辑器使用:type属性识别它,就像Text和Image组件一样。在SPA编辑器中,可以使用布局模式重新调整组件大小的相同功能。
-
返回至http://localhost:4502/editor.html/content/wknd-spa-angular/us/en/home.html。 添加其他 图像 组件,然后尝试使用 布局 选项重新调整其大小:
-
重新打开JSON模型http://localhost:4502/content/wknd-spa-angular/us/en.model.json,并观察作为JSON一部分的
columnClassNames:
类名
aem-GridColumn--default--4指示组件应基于12列网格为4列宽。 有关响应式网格的更多详细信息见此处。 -
返回到IDE,在
ui.apps模块中ui.apps/src/main/content/jcr_root/apps/wknd-spa-angular/clientlibs/clientlib-grid处定义了客户端库。 打开文件less/grid.less。此文件确定 布局容器 使用的断点(
default、tablet和phone)。 此文件将根据项目规范进行自定义。 当前断点设置为1200px和650px。 -
您应该能够使用
Text组件的响应式功能和更新的富文本策略来创作类似于以下内容的视图:
恭喜! congratulations
恭喜,您已了解如何将SPA组件映射到AEM组件,并且实施了新的Image组件。 您还有机会探索 布局容器 的响应式功能。
您始终可以在GitHub上查看完成的代码,或通过切换到分支Angular/map-components-solution在本地签出代码。
后续步骤 next-steps
导航和路由 — 了解如何使用SPA Editor SDK映射到AEM Pages,从而支持SPA中的多个视图。 动态导航是使用Angular路由器实现的,并添加到现有的报头组件中。
额外练习 — 将配置保留到源代码管理 bonus
在许多情况下,尤其是在AEM项目开始时,将配置(如模板和相关内容策略)保留到源代码控制中很有价值。 这可确保所有开发人员都针对同一组内容和配置工作,额外确保环境之间的一致性。 只要项目达到了一定的成熟度,管理模板的实践工作就可以移交给一个专门的高级用户组。
接下来的几个步骤将使用Visual Studio Code IDE和VSCode AEM Sync执行,但可以使用任何工具和您已配置为从AEM的本地实例 提取 或 导入 内容的任何IDE执行。
-
在Visual Studio Code IDE中,确保已通过Marketplace扩展安装VSCode AEM Sync:
-
在项目资源管理器中展开 ui.content 模块并导航到
/conf/wknd-spa-angular/settings/wcm/templates。 -
右键单击
templates文件夹,然后选择从 AEM 服务器导入:
-
重复导入内容的步骤,但选择位于
/conf/wknd-spa-angular/settings/wcm/policies的 策略 文件夹。 -
检查位于
ui.content/src/main/content/META-INF/vault/filter.xml的filter.xml文件。code language-xml <!--ui.content filter.xml--> <?xml version="1.0" encoding="UTF-8"?> <workspaceFilter version="1.0"> <filter root="/conf/wknd-spa-angular" mode="merge"/> <filter root="/content/wknd-spa-angular" mode="merge"/> <filter root="/content/dam/wknd-spa-angular" mode="merge"/> <filter root="/content/experience-fragments/wknd-spa-angular" mode="merge"/> </workspaceFilter>filter.xml文件负责识别随包安装的节点的路径。 请注意每个筛选器上的mode="merge",这表示现有内容将不会被修改,而是只会添加新内容。 由于内容作者可能会更新这些路径,因此代码部署 不会 覆盖内容,这一点很重要。 查看 FileVault 文档,了解有关使用过滤器元素的更多详细信息。比较
ui.content/src/main/content/META-INF/vault/filter.xml和ui.apps/src/main/content/META-INF/vault/filter.xml,了解每个模块管理的不同节点。