可视化内容片段 — 模板 visual-content-fragments-templates

在Adobe Experience Manager (AEM) as a Cloud Service中,HTML模板可用于可视化内容片段,并以HTML格式交付它们。

NOTE
可视化内容片段和可视化内容片段图形作业当前处于“有限可用”状态。
如果您想参加,请将您的正式电子邮件地址发送至experience-production-agent@adobe.com的请求。

HTML模板允许您控制内容片段的显示方式。 您可以在选择的代码编辑器中创建HTML模板,然后上传这些模板并将其分配给AEM中的内容片段模型。 使用Handlebars.js的内容占位符允许将模板映射到内容片段模型中的数据类型。 将模板分配给模型后,即可与基于模型的任何内容片段一起使用,以可视化片段或将其作为HTML格式的模块化体验交付到任何渠道,例如Web、电子邮件、移动应用程序或其他渠道。

本文介绍了如何使用Handlebars语法创建自定义HTML模板以呈现可视化内容片段。

创建模板后,您可以:

NOTE
查看可视化内容片段,以便在AEM中上传、分配和使用您的模板。
NOTE
使用Figma to Visual Content Fragments作业自动加载HTML设计。

您将学习的内容 what-you-will-learn

在向(非常快速地)介绍以下内容后:

  • 如何在AEM中使用模板
  • 使用发布URL

本页涵盖(更详细):

  • Handlebars — 语法的必要基础知识
  • 如何访问内容片段数据
  • 使用嵌套内容片段
  • 处理多值字段
  • 创建循环和条件逻辑
  • 内容片段的模板设计最佳实践

先决条件 prerequisites

要了解并使用此处介绍的技术,您应该拥有:

  • 对HTML的基本了解
  • 熟悉AEM内容片段和内容片段模型
  • 了解您的内容片段模型

使用内容片段HTML模板 using-a-content-fragment-html-template

在AEM中使用内容片段HTML模板 using-a-content-fragment-html-template-in-aem

有关如何在AEM中使用模板的详细信息,请参阅:

使用可视化内容片段发布URL using-the-visual-content-fragment-publish-url

使用该模板创建可视内容片段后,您可以使用可视内容片段的发布URL

Handlebars - (非常)基础知识 handlebars-the-very-basics

Handlebars是一种简单的模板语言,它使用双大括号(括号) {{ }}将动态内容插入到HTML中。

基本语法 basic-syntax

基本Handlebars语法的示例:

<!-- Output a variable (HTML-escaped) -->
{{snippet-not-found:variableName}}

<!-- Output raw HTML (unescaped) -->
{{{htmlContent}}}

<!-- Comment (not rendered) -->
{{! This is a comment }}

重要概念 key-concepts

Handlebars的主要概念:

语法
描述
何时使用
{{ }}
转义HTML特殊字符
元数据、标签、布尔值
{{{ }}}
输出原始HTML(未转义)
富文本和资产输出
{{! }}
仅Handlebars注释
模板文档
IMPORTANT
对字段值使用三大括号({{{ }}}),因为值是预渲染的HTML。

模板上下文引用 template-context-reference

呈现模板时,它会接收一个上下文对象,其中包含有关您的内容片段的所有数据。 这将涵盖:

  • 您选择的片段

  • 从该选定片段引用的所有后续片段

    note
    NOTE
    可以引用片段:
    • 在UI中:最大深度为5
    • 使用API时:深度可配置,最大深度为10

内容片段 content-fragment

(所选)内容片段的上下文对象的结构:

变量
类型
描述
properties
地图
片段元数据(请参阅属性结构
fields
地图
按名称直接访问字段值
allFields
列表
迭代的{name, value}数组
hasFields
布尔值
如果片段包含字段,则为true

属性结构 properties-structure

properties对象对于选定片段和每个引用的片段具有相同的结构。

属性
类型
描述
示例
id
字符串
片段的UUID
title
字符串
片段的标题
骑自行车去犹他州南部
description
字符串
片段的描述
一次冒险……
path
字符串
片段的JCR路径
/content/dam/...
hasDescription
布尔值
如果描述不为空,则为真
true
createdDate
字符串
ISO-8601创建日期
modifiedDate
字符串
ISO-8601修改日期
publishedDate
字符串
ISO-8601发布日期
status
字符串
发布层的复制状态
DRAFT
model
地图
包含: idpathnametechnicalNamedescription
validationStatus
列表
{property, message}等条目
previewReplicationStatus
字符串
预览层的复制状态
tags
列表
片段级别标记。 每个项目: idtitletitlePathnamepathdescription
fieldTags
列表
字段级标记。 与tags的结构相同。

示例:模板访问

对于(选定的)内容片段:

{{properties.title}}, {{properties.description}}, {{{fields.field_name}}}

引用的内容片段 referenced-content-fragments

任何引用片段的上下文对象的结构:

变量
类型
描述
hasReferencedFragments
布尔值
存在引用时为true
referencedFragments
列表
引用的片段对象数组
referencesError
布尔值
加载引用时出现错误时的true
referencesErrorMessage
字符串
referencesErrortrue时的错误消息

引用的片段结构 referenced-fragment-structure

referencedFragments中的每个项目都包含:

属性
类型
描述
anchorId
字符串
HTML安全锚点ID(在片段级别;不是内容片段属性)
properties
地图
片段元数据(与上述结构相同)
hasFields
布尔值
如果片段包含字段,则为真
fields
地图
直接访问此片段中的字段
allFields
列表
迭代的{name, value}数组

示例:第一个引用的内容片段(0索引列表中的第一个项目)的模板访问权限:

{{referencedFragments.[0].anchorId}}, {{referencedFragments.[0].properties.title}}, {{referencedFragments.[0].properties.description}}

或者,从字段映射中:

{{{ fields.referenced_cf_field_name.properties.description }}}

基本字段访问 basic-field-access

建议直接访问字段,如有必要,您可以循环访问所有字段。

使用字段映射直接按名称访问字段:

<!DOCTYPE html>
<html>
<head>
  <title>{{properties.title}}</title>
</head>
<body>
  <article>
    <h1>{{{fields.title}}}</h1>
    <p class="subtitle">{{{fields.subtitle}}}</p>
    <div class="content">
      {{{fields.description}}}
    </div>
    <div class="image">
      {{{fields.primaryImage}}}
    </div>
  </article>
</body>
</html>

请记住:

  • 如果字段值包含预呈现的HTML(富文本),请使用三大括号{{{ }}}
  • 字段名称(标题、子标题、描述、主图像)必须​与您的内容片段模型​完全匹配
  • 未呈现缺少的字段 — 不引发任何错误,并且在呈现的HTML片段中,Handlebars语法仍然存在(并且可见)

循环访问所有字段 iterate-through-all-fields

如果您事先不知道字段名称,请使用allFields

<table>
  <thead>
    <tr>
      <th>Field Name</th>
      <th>Field Value</th>
    </tr>
  </thead>
  <tbody>
    {{#each allFields}}
    <tr>
      <td>{{name}}</td>
      <td>{{{value}}}</td>
    </tr>
    {{/each}}
  </tbody>
</table>

请记住:

  • {{name}}使用双大括号(纯文本标签)
  • {{{value}}}使用三大括号(预渲染的HTML值)

嵌套内容片段 nested-content-fragments

当内容片段字段引用另一个内容片段时,您可以使用点表示法直接访问引用的片段中的字段。

单层嵌套 single-level-nesting

单级嵌套示例:

<article>
  <h1>{{{fields.title}}}</h1>

  <!-- Access author (a referenced Content Fragment) -->
  <div class="author-info">
    <h3>Author</h3>
    <p>Name: {{{fields.author.name}}}</p>
    <p>Email: {{{fields.author.email}}}</p>
    <p>Bio: {{{fields.author.bio}}}</p>
  </div>

  <div class="content">
    {{{fields.content}}}
  </div>
</article>

模式: fields.referenceFieldName.nestedFieldName

多级嵌套 multi-level-nesting

系统支持无限的嵌套深度:

<article>
  <h1>{{{fields.title}}}</h1>

  <div class="author-details">
    <!-- Level 1: Author -->
    <p>Author: {{{fields.author.name}}}</p>

    <!-- Level 2: Author's Organization -->
    <p>Organization: {{{fields.author.organization.name}}}</p>
    <p>Website: {{{fields.author.organization.website}}}</p>

    <!-- Level 3: Organization's Address -->
    <p>Located in: {{{fields.author.organization.address.city}}},
    {{{fields.author.organization.address.country}}}</p>
  </div>

  <div class="content">
    {{{fields.content}}}
  </div>
</article>

模式: fields.level1.level2.level3.fieldName (有限的深度;默认值为5,使用API时可以扩展到10)

API参数要求:水化 api-parameter-requirements

要启用嵌套内容片段访问,必须在API调用中包含hydration查询参数:

要启用水化,请执行以下操作:

# Enable hydration with depth=2 for 2 levels of nesting
GET /adobe/sites/cf/fragments/{id}/preview?hydration=%7B%22enabled%22%3Atrue%2C%22maxDepth%22%3A2%7D
maxDepth
加载的内容
1
主片段+直接引用
2
主片段+直接引用+其引用
3+
最多继续10个级别

多值字段 multi-valued-fields

多值字段有多种类型。

多值文本字段 multi-valued-text-fields

多值时文本、数字、日期和其他简单字段变为数组:

<article>
  <h1>{{{fields.title}}}</h1>

  <!-- Access individual items by index (use dot before bracket) -->
  <div class="tags">
    <span class="tag">{{{fields.tags.[0]}}}</span>
    <span class="tag">{{{fields.tags.[1]}}}</span>
  </div>

  <!-- Better: Iterate through all tags -->
  <div class="tags">
    {{#each fields.tags}}
    <span class="tag">{{{this}}}</span>
    {{/each}}
  </div>
</article>

请记住,在Handlebars中按索引访问数组项时:

  • 使用:
    • .[0] (括号前的点)
  • 非:
    • [0]

多值数字字段 multi-valued-number-fields

数字将转换为字符串以进行渲染:

<div class="pricing">
  <h3>Available Prices:</h3>
  {{#each fields.prices}}
  <span class="price">${{{this}}}</span>
  {{/each}}
</div>

多值内容片段引用 multi-valued-content-fragment-references

当字段引用多个内容片段时:

<div class="authors">
  <h3>Authors:</h3>
  {{#each fields.authors}}
  <div class="author">
    <h4>{{{this.name}}}</h4>
    <p>Email: {{{this.email}}}</p>
    {{#if this.bio}}
    <p class="bio">{{{this.bio}}}</p>
    {{/if}}
  </div>
  {{/each}}
</div>

多值资产引用 multi-valued-asset-references

为作为资源的内容类型(例如,图像和文档)配置的内容引用字段将预呈现为HTML。 多值资产变为数组:

<!-- Single asset -->
<div class="hero-image">
  {{{fields.heroImage}}}
</div>

<!-- Multi-valued: iterate through all images -->
<div class="gallery">
  {{#each fields.gallery}}
  <div class="image">{{{this}}}</div>
  {{/each}}
</div>

嵌套的多值引用 nested-multi-valued-references

多值引用可以包含任何深度的多值引用:

{{#each fields.chapters}}
<div class="chapter">
  <h3>Chapter: {{{this.title}}}</h3>

  {{#each this.authors}}
  <p>Author: {{{this.name}}}</p>

  {{#each this.publications}}
  <p>Publication: {{{this.title}}}</p>
  {{/each}}
  {{/each}}
</div>
{{/each}}

循环和迭代 loops-and-iteration

Handlebars提供了用于迭代数组与对象的{{#each}}帮助程序。

对阵列进行迭代 iterating-over-arrays

循环访问数组的示例:

<!-- Simple array iteration -->
{{#each fields.tags}}
<span class="tag">{{{this}}}</span>
{{/each}}

<!-- Array of objects -->
{{#each fields.authors}}
<div class="author">
  <h4>{{{this.name}}}</h4>
  <p>{{{this.email}}}</p>
</div>
{{/each}}

<!-- With empty-state fallback -->
{{#each fields.tags}}
<span class="tag">{{{this}}}</span>
{{snippet-not-found:else}}
<p>No tags available.</p>
{{/each}}

循环中的特殊变量 special-variables-in-loops

{{#each}}块内,Handlebars提供特殊变量:

{{#each fields.items}}
<div class="item">
  <p>Index: {{@index}}</p>     <!-- 0-based index -->
  <p>Number: {{@number}}</p>   <!-- 1-based index -->
  <p>First: {{@first}}</p>     <!-- true for first item -->
  <p>Last: {{@last}}</p>       <!-- true for last item -->
  <p>Value: {{{this}}}</p>     <!-- current item -->
</div>
{{/each}}

<!-- Example: numbered steps with first/last CSS classes -->
<ul>
  {{#each fields.steps}}
  <li class="{{#if @first}}first{{/if}} {{#if @last}}last{{/if}}">
    Step {{@number}}: {{{this}}}
  </li>
  {{/each}}
</ul>

迭代引用的片段 iterating-over-referenced-fragments

迭代引用的片段的示例:

{{#if hasReferencedFragments}}
<section class="references">
  <h2>Related Content</h2>
  {{#each referencedFragments}}
  <article id="{{anchorId}}">
    <h3>{{title}}</h3>
    {{#if hasDescription}}
    <p>{{description}}</p>
    {{/if}}
    {{#if hasFields}}
    <ul>
      {{#each allFields}}
      <li><strong>{{name}}:</strong> {{{value}}}</li>
      {{/each}}
    </ul>
    {{/if}}
  </article>
  {{/each}}
</section>
{{/if}}

嵌套循环 nested-loops

嵌套循环的示例:

{{#each fields.categories}}
<section class="category">
  <h2>{{{this.name}}}</h2>

  {{#each this.products}}
  <article class="product">
    <h3>{{{this.name}}}</h3>
    <p>{{{this.description}}}</p>
  </article>
  {{/each}}
</section>
{{/each}}

条件渲染 conditional-rendering

使用条件根据数据可用性显示或隐藏内容。

基本If/Else basic-if-else

基本if-else构造的示例:

{{#if hasMainDescription}}
<p class="description">{{properties.description}}</p>
{{snippet-not-found:else}}
<p class="no-description">No description available.</p>
{{/if}}

<!-- Check field existence before rendering -->
{{#if fields.author}}
<div class="author">
  <p>By {{{fields.author.name}}}</p>
</div>
{{/if}}

{{#if fields.publishDate}}
<time>{{{fields.publishDate}}}</time>
{{/if}}

Unless(负条件) unless-negative-conditional

unless辅助函数:

<!-- Show author unless explicitly hidden -->
{{#unless fields.hideAuthor}}
<div class="author">{{{fields.author.name}}}</div>
{{/unless}}

嵌套条件 nested-conditials

嵌套条件示例:

{{#if fields.author}}
<div class="author">
  <h3>{{{fields.author.name}}}</h3>

  {{#if fields.author.bio}}
  <p class="bio">{{{fields.author.bio}}}</p>
  {{/if}}

  {{#if fields.author.website}}
  <a href="{{{fields.author.website}}}">Visit Website</a>
  {{/if}}
</div>
{{/if}}

内置Handlebars帮助程序 built-in-handlebars-helpers

Handlebars包含多个内置帮助程序,超出{{#if}}{{#each}}

辅助函数
描述
{{#if condition}}
如果条件为真,则呈现内容。 假值: falseundefinednull0""[]
{{#unless condition}}
如果条件为假(与#if相反),则呈现内容
{{#each array}}
为每个项目重复内容;对于空数组支持{{else}}
{{#with object}}
为嵌套对象创建新的范围,减少路径重复
{{lookup this "key"}}
按名称动态查找属性

使用辅助函数 with-helper

为嵌套对象创建新的范围,以减少重复的路径前缀:

{{#with fields.author}}
<div class="author">
  <h3>{{{name}}}</h3>     <!-- same as fields.author.name -->
  <p>{{{email}}}</p>      <!-- same as fields.author.email -->
  <p>{{{bio}}}</p>        <!-- same as fields.author.bio -->
</div>
{{/with}}

<!-- Useful for deeply nested objects -->
{{#with fields.author.organization}}
<div class="organization">
  <h4>{{{name}}}</h4>
  <p>{{{website}}}</p>
  {{#with address}}
  <address>
    {{{street}}}<br/>
    {{{city}}}, {{{country}}}
  </address>
  {{/with}}
</div>
{{/with}}

前进模式 advanced-patterns

下面是高级模式的一些示例。

访问嵌套循环中的父上下文 accessing-parent-context-in-nested-loops

使用../从嵌套循环内访问父作用域:

<h1>{{{fields.title}}}</h1>

{{#each fields.chapters}}
<section class="chapter">
  <h2>Chapter {{@number}}: {{{this.title}}}</h2>

  {{#each this.sections}}
  <article>
    <!-- Access parent chapter via ../ -->
    <p>Chapter: {{{../title}}}</p>

    <!-- Access root context via ../../ -->
    <p>Book: {{{../../fields.title}}}</p>

    <h3>{{{this.title}}}</h3>
    <div>{{{this.content}}}</div>
  </article>
  {{/each}}
</section>
{{/each}}

动态CSS类 dynamic-css-classes

动态CSS类的示例:

<article class="content-fragment {{#if hasMainDescription}}with-description{{/if}} {{#if hasReferencedFragments}}has-refs{{/if}}">
  <h1>{{properties.title}}</h1>
</article>

<ul class="tag-list">
  {{#each fields.tags}}
  <li class="tag {{#if @first}}first{{/if}} {{#if @last}}last{{/if}}">
    {{{this}}}
  </li>
  {{/each}}
</ul>

完整示例 complete-examples

提供了几个完整的示例以供参考。

有作者的博客帖子

包含作者详细信息的博客帖子:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>{{properties.title}}</title>
  <style>
    body { font-family: Arial, sans-serif; margin: 40px; }
    .author-card { background: #f5f5f5; padding: 20px; border-radius: 8px; }
    .tags { display: flex; gap: 10px; }
    .tag { background: #007bff; color: white; padding: 5px 10px; border-radius: 4px; }
  </style>
</head>
<body>
  <article>
    <header>
      <h1>{{{fields.title}}}</h1>
      {{#if fields.publishDate}}
      <time datetime="{{{fields.publishDate}}}">{{{fields.publishDate}}}</time>
      {{/if}}
      {{#if fields.tags}}
      <div class="tags">
        {{#each fields.tags}}
        <span class="tag">{{{this}}}</span>
        {{/each}}
      </div>
      {{/if}}
    </header>

    {{#if fields.heroImage}}
    <figure>
      {{{fields.heroImage}}}
      {{#if fields.imageCaption}}
      <figcaption>{{{fields.imageCaption}}}</figcaption>
      {{/if}}
    </figure>
    {{/if}}

    <div class="content">
      {{{fields.content}}}
    </div>

    {{#if fields.author}}
    <aside class="author-card">
      <h3>About the Author</h3>
      <h4>{{{fields.author.name}}}</h4>
      {{#if fields.author.profilePicture}}
      <div class="author-image">{{{fields.author.profilePicture}}}</div>
      {{/if}}
      {{#if fields.author.bio}}
      <p>{{{fields.author.bio}}}</p>
      {{/if}}
      {{#if fields.author.email}}
      <p>Contact: <a href="mailto:{{{fields.author.email}}}">{{{fields.author.email}}}</a></p>
      {{/if}}
    </aside>
    {{/if}}
  </article>
</body>
</html>

所需的API调用:

GET /adobe/sites/cf/fragments/{id}/preview?hydration=%7B%22enabled%22%3Atrue%2C%22maxDepth%22%3A1%7D

通用表视图(事先不了解字段) generic-table-view-no-prior-knowledge-of-fields

一种通用的表格视图,它不具备字段的内在知识。 与​ 通用模板 ​类似:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>{{properties.title}}</title>
  <style>
    body { font-family: Arial, sans-serif; margin: 40px; }
    table { width: 100%; border-collapse: collapse; margin: 20px 0; }
    th, td { border: 1px solid #ddd; padding: 12px; text-align: left; }
    th { background-color: #f4f4f4; font-weight: bold; }
    .ref-section { background: #f9f9f9; padding: 20px; margin: 20px 0; border-radius: 8px; }
  </style>
</head>
<body>
  <header>
    <h1>{{properties.title}}</h1>
    {{#if properties.description}}<p>{{properties.description}}</p>{{/if}}
    <p><small>Path: {{properties.path}}</small></p>
  </header>

  {{#if hasFields}}
  <section>
    <h2>Fields</h2>
    <table>
      <thead>
        <tr><th>Field Name</th><th>Field Value</th></tr>
      </thead>
      <tbody>
        {{#each allFields}}
        <tr>
          <td><strong>{{name}}</strong></td>
          <td>{{{value}}}</td>
        </tr>
        {{/each}}
      </tbody>
    </table>
  </section>
  {{/if}}

  {{#if hasReferencedFragments}}
  <section class="ref-section">
    <h2>Referenced Content Fragments</h2>
    {{#each referencedFragments}}
    <article id="{{anchorId}}" style="margin-bottom: 30px;">
      <h3>{{title}}</h3>
      {{#if hasDescription}}<p>{{description}}</p>{{/if}}
      <p><small>Path: {{path}}</small></p>
      {{#if hasFields}}
      <table>
        <thead>
          <tr><th>Field Name</th><th>Field Value</th></tr>
        </thead>
        <tbody>
          {{#each allFields}}
          <tr>
            <td><strong>{{name}}</strong></td>
            <td>{{{value}}}</td>
          </tr>
          {{/each}}
        </tbody>
      </table>
      {{/if}}
    </article>
    {{/each}}
  </section>
  {{/if}}
</body>
</html>

最佳实践 best-practices

最佳实践包括:

  1. 对于包含HTML标记内容的字段值,始终使用三大括号。

    • 字段值在HTML中预呈现。

      note
      NOTE
      双大括号将原始HTML标签显示为纯文本。
    code language-handlebars
    <!-- CORRECT -->
    {{{fields.description}}}
    
    <!-- WRONG - displays HTML tags as text -->
    {{fields.description}}
    
  2. 在访问嵌套字段之前检查是否存在。

    code language-handlebars
    <!-- GOOD: check before accessing nested fields -->
    {{#if fields.author}}
    <p>By {{{fields.author.name}}}</p>
    {{/if}}
    
    <!-- RISKY: may render empty if author is not set -->
    <p>By {{{fields.author.name}}}</p>
    
  3. 尽可能使用直接字段访问。

    • 它比迭代allFields并按名称匹配更易读取和维护。
  4. 带部分注释的结构模板。

    code language-handlebars
    {{! ===== HEADER SECTION ===== }}
    <header>
      <h1>{{properties.title}}</h1>
    </header>
    
    {{! ===== MAIN CONTENT ===== }}
    <main>
      {{#if hasFields}}
      <!-- fields rendering -->
      {{/if}}
    </main>
    
    {{! ===== REFERENCES ===== }}
    {{#if hasReferencedFragments}}
    <!-- references rendering -->
    {{/if}}
    
  5. 使用回退轻松处理缺失数据。

    code language-handlebars
    {{#if fields.title}}
    <h1>{{{fields.title}}}</h1>
    {{snippet-not-found:else}}
    <h1>Untitled</h1>
    {{/if}}
    
  6. 始终使用正确的HTML文档结构。

    code language-handlebars
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>{{properties.title}}</title>
    </head>
    <body>
      <!-- your content here -->
    </body>
    </html>
    
  7. 通过多种内容方案进行测试:

    • 所有字段已完全填充
    • 可选字段缺失
    • 清空多值字段
    • 深度嵌套(多级)
    • 无法加载的引用
  8. 使用语义HTML元素:

    • 为了获得更好的辅助功能,请使用<article><header><main><footer><time><address>或类似项。
  9. 将样式保留在CSS中。

    • 使用<style>标记或外部样式表。
    • 尽可能避免使用内联样式。
  10. 记录复杂逻辑:

    • 使用Handlebars注释({{! }})
    • 请勿使用HTML注释,这些注释会显示在渲染的输出中。

疑难解答 troubleshooting

一些故障排除提示包括:

问题
症状
解决方案
字段以文本形式显示HTML标记
<p>Hello World</p>按字面显示
使用三大括号: {{{fields.description}}}
嵌套的内容片段字段为空或显示[对象Object]
{{{fields.author.name}}}为空
在API调用中启用水合;验证字段名称拼写;检查maxDepth是否足够深
多值字段仅显示第一项
具有五个项目的数组仅呈现一个
使用{{#each fields.tags}}迭代所有项
数组索引访问不起作用
{{{fields.tags[0]}}}呈现为空
使用点括号语法: {{{fields.tags.[0]}}}
引用的片段未出现
hasReferencedFragments始终为false
启用水合: ?hydration=%7B%22enabled%22%3Atrue%7D;还检查{{#if referencesError}}
模板不呈现任何内容
空页面或空输出
检查未关闭的{{#if}}{{#each}}块;添加诊断输出: <pre>hasFields: {{hasFields}} | title: {{properties.title}}</pre>
评论会显示在渲染的页面中
对最终用户可见的HTML注释文本
使用Handlebars注释{{! comment }}而不是HTML <!-- comment -->
条件属性的计算结果始终为true
{{#if fields.enabled}}始终为真
注意:字符串"false"在Handlebars中为truthy。 只有实际的falsenullundefined0""[]是假的。
特殊字符作为实体呈现
显示&lt;&amp;而不是<&
对预渲染的HTML内容使用三大括号: {{{fields.content}}}
无法从内环访问外环变量
来自父级#each的变量未定义
../用于父作用域: {{{../name}}};将../../用于祖父
空列表未显示回退消息
零项的多值字段不显示任何内容
{{#each}}中使用{{else}}{{#each fields.tags}}...{{else}}<p>No tags</p>{{/each}}

使用资产 working-with-assets

从内容片段引用的Assets将由AEM预呈现为HTML。 因此,所有资产参考都必须使用三大括号。

资源类型
呈现为
图像
<img src="..." alt="...">
视频
<video>元素
文档
<a href="...">链接

请记住:

  • 资产字段始终使用三大括号。
    使用双大括号将转义生成的HTML标记,并将其显示为原始文本,而不是呈现图像、视频或链接。

资源字段使用情况 asset-field-usage

资源字段用法示例:

<!-- CORRECT - triple braces render the image -->
{{{fields.heroImage}}}
<!-- Output: <img src="path/to/image.jpg" alt="Hero"> -->

<!-- WRONG - double braces escape the tag, showing it as text -->
{{fields.heroImage}}
<!-- Output: &lt;img src="path/to/image.jpg" alt="Hero"&gt; -->

自定义模板帮助程序 customer-template-helpers

系统提供自定义Handlebars帮助程序,用于生成具有自定义HTML属性的HTML元素。 这些帮助程序让您能够控制生成的标记,同时处理从预呈现内容中提取源URL的复杂性。

可用的帮助程序:

  1. asset — 生成具有自定义属性的<img>标记
  2. text — 生成<span>标记,这些标记将文本内容与自定义属性环绕

asset帮助程序 asset-helper

语法:

{{{asset fieldValue attribute1="value1" attribute2="value2"}}}

请记住:

  • 资产帮助程序使用三大括号{{{ }}},而不是双大括号!

四个基本示例 four-basic-examples

四个基本示例包括:

<!-- Add a CSS class to an image -->
{{{asset fields.heroImage class="hero-image"}}}
<!-- Output: <img src="..." alt="..." class="hero-image"> -->

<!-- Add multiple CSS classes -->
{{{asset fields.productImage class="product-img responsive shadow"}}}

<!-- Add id and class -->
{{{asset fields.logo class="brand-logo" id="main-logo"}}}

<!-- Add data attributes -->
{{{asset fields.thumbnail class="thumb" data-category="product" data-id="123"}}}

支持的属性 supported-attributes

您可以添加任何有效的HTML属性:

属性
示例
class
class="my-class another-class"
id
id="unique-id"
alt
alt="Custom alt text" (overrides existing alt)
data-*
data-index="1" data-type="hero"
aria-*
aria-label="Description" aria-hidden="true"
width
width="300"
height
height="200"
loading
loading="lazy"
style
style="border-radius: 8px;"

覆盖替换文本 override-alt-text

可以覆盖原始图像中的alt属性:

{{{asset fields.photo alt="Custom description for accessibility"}}}

复杂示例 complex-example

一个复杂的示例是:

<article class="blog-post">
<header>
{{{asset fields.featuredImage
class="featured-image responsive"
id="post-hero"
loading="lazy"
data-post-id="12345"}}}
</header>
</article>

与循环一起使用 using-with-loops

循环中的资产帮助程序:

{{#each fields.galleryImages}}
{{{asset this class="gallery-item" data-index=@index}}}
{{/each}}

text帮助程序 text-helper

文本帮助程序生成一个包含自定义CSS类和HTML属性的文本内容换行的<span>标记。 用于设置单个文本字段的样式。

语法:

{{{text fieldValue attribute1="value1" attribute2="value2"}}}

请记住:

  • 文本辅助函数使用三大括号{{{ }}},而不是双大括号!

三个基本示例 three-basic-examples

三个基本示例包括:

<!-- Add a CSS class to text -->
{{{text fields.title class="article-title"}}}
<!-- Output: <span class="article-title">The Title Text</span> -->

<!-- Add multiple attributes -->
{{{text fields.price class="price-tag" id="product-price" data-currency="USD"}}}

<!-- Style inline text -->
{{{text fields.highlightedText class="highlighted" style="background: yellow;"}}}

常见用例 common-use-cases

一些常见用例包括:

<!-- Styling article metadata -->
<article>
<header>
{{{text fields.category class="category-badge"}}}
<h1>{{{fields.title}}}</h1>
{{{text fields.author class="byline"}}}
{{{text fields.publishDate class="date"}}}
</header>
</article>

<!-- Creating styled labels -->
<div class="product-card">
{{{text fields.productName class="product-name"}}}
{{{text fields.brand class="brand-label" data-brand-id="abc"}}}
{{{text fields.price class="price" id="main-price"}}}
</div>

<!-- Accessibility enhancements -->
{{{text fields.importantNote class="alert" role="alert" aria-live="polite"}}}

带循环 with-loops

循环的常见用例包括:

{{#each fields.tags}}
{{{text this class="tag-badge"}}}
{{/each}}

帮助程序 — 属性验证 helpers-attribute-validation

两个帮助程序都会先验证属性名称,然后再将其包含在输出中。

有效的属性名称:

  • 必须以字母(a-z、A-Z)开头

  • 只能包含字母、数字、连字符和下划线;请参阅命名约定

  • 区分大小写

  • 例如:

    • 有效:
      • class, id, data-value, aria-label, my_attr, dataIndex1
    • 无效:
      • 123-attr, -class, @special, $money

将以静默方式跳过无效的属性名称,日志中会显示警告:

{{{asset fields.image class="valid" 123-invalid="skipped" id="also-valid"}}}
<!-- Output: <img src="..." alt="..." class="valid" id="also-valid"> -->
<!-- 123-invalid is skipped because it starts with a number -->

请记住:

  • 检查服务器日志中是否存在“阻止的无效属性名称格式”警告。

比较直接输出与帮助程序 comparing-direct-output-to-helpers

何时添加直接输出{{{fields.xxx}}}

  • 您不需要自定义样式
  • 您希望默认输出保持不变
  • 该字段包含您不想修改的复杂HTML

何时使用辅助函数:

  • 您需要添加用于样式设置的CSS类
  • 您需要添加自定义HTML属性(data-*aria-*等)
  • 您需要一致的、受控制的HTML结构

比较:

<!-- Direct output - uses whatever HTML the system generates -->
{{{fields.heroImage}}}
<!-- Output: <img src="/path/image.jpg" alt="Hero Image"> -->

<!-- With asset helper - full control over attributes -->
{{{asset fields.heroImage class="hero responsive" id="main-hero" loading="lazy"}}}
<!-- Output: <img src="/path/image.jpg" alt="Hero Image" class="hero responsive" id="main-hero" loading="lazy"> -->

快速参考 quick-reference

提供了一些快速参考信息以供参考。

上下文变量 context-variables

上下文变量:

{{properties}}                <!-- Main fragment metadata -->
{{fields}}                    <!-- Map keyed by field name to rendered values (such as strings, lists, nested maps for Content Fragment references, commerce maps, HTML, and others) -->
{{allFields}}                 <!-- List of { name, value } maps (uniform iteration) -->
{{hasFields}}.                <!-- Boolean -->
{{hasReferencedFragments}}.   <!-- Boolean -->
{{referencedFragments}}       <!-- List of referenced-fragment maps -->

字段访问 field-access

如何访问字段:

{{{fields.fieldName}}}                    <!-- Direct field -->
{{{fields.author.name}}}                  <!-- Nested Content Fragment field -->
{{{fields.author.org.address.city}}}      <!-- Multi-level nesting -->
{{{fields.tags.[0]}}}                     <!-- Array by index -->
{{#each fields.tags}}...{{/each}}         <!-- Array iteration -->
{{{fields.authors.[0].name}}}             <!-- Multi-valued Content Fragment reference -->

控制流 control-flow

控制流:

{{#if condition}}...{{/if}}               <!-- Conditional -->
{{#if condition}}...{{else}}...{{/if}}    <!-- If/else -->
{{#unless condition}}...{{/unless}}       <!-- Negative conditional -->
{{#each array}}...{{/each}}               <!-- Iteration -->
{{#each array}}...{{else}}...{{/each}}    <!-- Iteration with fallback -->
{{#with object}}...{{/with}}              <!-- Change scope -->

循环变量 loop-variables

循环变量:

{{@index}}        <!-- 0-based index -->
{{@number}}       <!-- 1-based index -->
{{@first}}        <!-- true for first item -->
{{@last}}         <!-- true for last item -->
{{@key}}          <!-- Object property name -->
{{this}}          <!-- Current item -->
{{../parent}}     <!-- Access parent scope -->

自定义模板帮助程序 custom-template-helpers

自定义模板帮助程序:

{{{asset fields.image class="css-class"}}}                <!-- Image with class -->
{{{asset fields.image class="c1" id="my-id"}}}            <!-- Image with multiple attrs -->
{{{asset fields.image alt="Custom alt text"}}}            <!-- Override alt text -->
{{{asset fields.image loading="lazy" data-x="val"}}}      <!-- Custom attributes -->

{{{text fields.title class="title-class"}}}               <!-- Span with class -->
{{{text fields.price class="price" id="p1"}}}             <!-- Span with multiple attrs -->
{{{text this class="item" data-index=@index}}}            <!-- In loops -->

其他资源 additional-resources

其他资源可供使用:

recommendation-more-help
experience-manager-cloud-service-help-main-toc