关于 aem-component-development
面向开发者和编码 Agent 的 Adobe Experience Manager 组件开发技能,涵盖组件结构、实现流程、继承方式与内容编辑规范。
主要功能
- 01组件文件结构与定义
- 02Sling Model 和 HTL 实现
- 03Touch UI 对话框指南
- 04Core Component 继承模式
- 05编辑占位符与创作行为
适用场景
- 01创建新的 AEM 组件
- 02扩展现有 Core Component
- 03配置对话框和编辑行为
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ headwirecom/ aem-agent-skills --skill aem-component-development安装后在 Claude Code 中输入/aem-component-development确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/clientlibs.mddialogs.mdsling-models.md详细介绍
AEM 组件开发
AEM 组件是页面内容的构建块。每个组件都是 JCR 中的一个 cq:Component
节点,将以下内容关联起来:
- HTL 标记 — 渲染模板(
.html文件) - Sling Model — 服务端业务逻辑(Java)
- 对话框 — 用于编辑内容的作者界面(
cq:dialog) - 客户端库 — 前端行为所需的 CSS/JS
- 编辑配置 — 作者工具栏行为(
cq:editConfig)
前置技能: 本技能假设你了解 HTL。加载 htl-scripting 技能,了解表达式语法、块语句、XSS 上下文和全局对象。
组件文件结构
标准 Maven 原型布局(Touch UI,现代 AEM):
ui.apps/src/main/content/jcr_root/apps/<project>/components/<component-name>/
├── .content.xml ← cq:Component definition (title, group, supertype)
├── <component-name>.html ← HTL rendering script
├── _cq_dialog/
│ └── .content.xml ← Touch UI dialog (Granite UI)
├── _cq_editConfig/
│ └── .content.xml ← Edit behavior config
├── _cq_template/
│ └── .content.xml ← Default content on drag-and-drop
├── _cq_design_dialog/
│ └── .content.xml ← Policy/design dialog
└── clientlib/ ← Optional co-located clientlib
├── .content.xml
├── css.txt
├── js.txt
├── css/
└── js/
core/src/main/java/<package>/models/
└── <ComponentName>Model.java ← Sling Model
注意:带下划线的目录(_cq_dialog)是 JCR 节点(带冒号,如 cq:dialog)在文件系统中的表示形式。FileVault 序列化要求使用此命名方式。
组件定义(.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:primaryType="cq:Component"
jcr:title="My Component"
jcr:description="A description for authors"
componentGroup="My Project - Content"
sling:resourceSuperType="core/wcm/components/text/v2/text"/>
关键属性
| 属性 | 用途 |
|---|---|
jcr:title | 组件浏览器中的显示名称 |
jcr:description | 组件浏览器中的工具提示 |
componentGroup | 组件浏览器中的分组。使用 .hidden 可隐藏 |
sling:resourceSuperType | 继承其他组件(渲染、对话框、编辑配置) |
cq:isContainer | 若组件可包含子组件(例如 parsys),则设为 true |
cq:icon | 组件浏览器中使用的 Coral UI 图标名称 |
abbreviation | 未设置图标时使用的 2 字符缩写 |
Agent 工作流:创建新组件
第 1 步:定义组件节点
创建 .content.xml,设置 jcr:primaryType="cq:Component"、标题、分组,并可选地设置 sling:resourceSuperType 以扩展现有组件。
第 2 步:创建 Sling Model
在 core/ 模块中编写 Java Model 类。参见 references/sling-models.md。
@Model(adaptables = SlingHttpServletRequest.class,
adapters = MyComponent.class,
resourceType = "myproject/components/mycomponent",
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class MyComponentImpl implements MyComponent {
@ValueMapValue
private String title;
@ValueMapValue
private String description;
@Override
public String getTitle() { return title; }
@Override
public String getDescription() { return description; }
}
第 3 步:创建 HTL 脚本
<sly data-sly-use.model="com.myproject.core.models.MyComponent"/>
<div class="cmp-mycomponent"
data-sly-test="${model.title || model.description}">
<h2 class="cmp-mycomponent__title"
data-sly-test="${model.title}">${model.title}</h2>
<div class="cmp-mycomponent__description"
data-sly-test="${model.description}">
${model.description @ context='html'}
</div>
</div>
<sly data-sly-test="${!model.title && !model.description && (wcmmode.edit || wcmmode.preview)}">
<div class="cq-placeholder" data-emptytext="My Component"></div>
</sly>
第 4 步:创建对话框
完整的 Granite UI 字段参考,请参见 references/dialogs.md。
<?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="My Component"
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">
<title jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
fieldLabel="Title"
name="./title"/>
<description jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Description"
name="./description"/>
</items>
</column>
</items>
</columns>
</items>
</properties>
</items>
</tabs>
</items>
</content>
</jcr:root>
第 5 步:添加客户端库(如需要)
第 6 步:配置编辑行为(如需要)
<?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:primaryType="cq:EditConfig"
cq:actions="[edit,delete,insert,copymove]"
cq:layout="editbar"
cq:dialogMode="floating">
<cq:listeners jcr:primaryType="cq:EditListenersConfig"
afteredit="REFRESH_PAGE"
afterinsert="REFRESH_PAGE"/>
</jcr:root>
扩展现有组件
使用 sling:resourceSuperType 继承父组件的所有内容:
<jcr:root ...
jcr:primaryType="cq:Component"
jcr:title="Custom Text"
sling:resourceSuperType="core/wcm/components/text/v2/text"
componentGroup="My Project"/>
自动继承的内容:
- HTL 渲染脚本(通过 Sling 资源类型层级解析)
- 对话框(可通过 Sling Resource Merger 覆盖单个字段)
- 编辑配置、描述和图标
要覆盖对话框字段,只需在 _cq_dialog/ 下创建需要修改的节点,并在对话框根节点上设置 sling:resourceSuperType。Sling Resource Merger 会将你的修改与父组件合并。
Core Components
始终优先扩展 AEM Core Components,而不是从头构建。它们提供:
- 经过生产环境测试、无障碍且对 SEO 友好的标记
- BEM CSS 类命名(
cmp-<name>__<element>--<modifier>) - 用于 JSON/SPA 的 Sling Model 导出器
- Style System 支持
- Adobe Client Data Layer 集成
常见的可扩展 Core Components:
core/wcm/components/text/v2/textcore/wcm/components/image/v3/imagecore/wcm/components/title/v3/titlecore/wcm/components/teaser/v2/teasercore/wcm/components/list/v4/listcore/wcm/components/container/v1/containercore/wcm/components/page/v3/page
编辑占位符模式
即使组件为空,也必须在编辑模式下渲染可见内容:
<sly data-sly-use.template="core/wcm/components/commons/v1/templates.html"
data-sly-call="${template.placeholder @ isEmpty=!model.hasContent}"/>
或者使用手动回退方案:
<div class="cq-placeholder" data-emptytext="${component.properties.jcr:title}"
data-sly-test="${(wcmmode.edit || wcmmode.preview) && isEmpty}"></div>
内容模板(_cq_template/)
将组件拖到页面上时,预先填充组件的内容节点:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="nt:unstructured"
title="Default Title"
description="Edit this component"/>
资源类型解析
Sling 通过内容节点上的 sling:resourceType 解析组件:
- 内容节点的
sling:resourceType = "myproject/components/hero" - Sling 会查找
/apps/myproject/components/hero/hero.html - 如果未找到,则检查
sling:resourceSuperType链 - 最后回退到
/libs/搜索路径
资源类型为 myproject/components/hero 时的脚本解析顺序:
hero.html(与组件名称匹配)html.html(与扩展名匹配)GET.html(与方法和扩展名匹配)- 然后沿
sling:resourceSuperType链向上查找
关键规则
- 始终使用 Touch UI(
cq:dialog)——Classic UI 对话框已弃用。 - 优先使用 Sling Models,而非
WCMUsePojo——Sling Models 可测试、可缓存,是 AEM as a Cloud Service 的标准。 - 切勿修改
/libs——始终在/apps中创建覆盖。使用 Sling Resource Merger 进行部分覆盖。 - 组件没有内容时,始终渲染编辑占位符。
- CSS 类使用 BEM 命名:
cmp-<component>__<element>--<modifier>。 - 设置
componentGroup,否则组件不会显示在创作 UI 中。 - 对话框字段值的
name属性需使用./前缀(例如,name="./title"),以写入组件的内容节点。 - 从头构建之前,先扩展 Core Components。
/apps下的客户端库需要设置allowProxy=true,才能通过/etc.clientlibs/提供。
参考文件
- references/dialogs.md — Touch UI 对话框结构、Granite UI 字段类型、选项卡、验证
- references/clientlibs.md — 客户端库文件夹设置、类别、依赖项、HTL 引入
- references/sling-models.md — Sling Model 注解、注入策略、适配器、测试