시각적 컨텐츠 조각 - 템플릿 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 형식의 모듈식 환경으로 전달할 수 있습니다.

이 문서에서는 시각적 컨텐츠 조각을 렌더링하기 위해 Handlebars 구문을 사용하여 사용자 지정 HTML 템플릿을 만드는 방법에 대해 설명합니다.

템플릿을 만든 후 다음을 수행할 수 있습니다.

NOTE
AEM에서 템플릿을 업로드, 할당 및 사용하려면 시각적 콘텐츠 조각을 참조하십시오.
NOTE
시각적 콘텐츠 조각 구성 작업을(를) 사용하여 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
포함: id, path, name, technicalName, description
validationStatus
목록
{property, message}과(와) 같은 항목
previewReplicationStatus
문자열
미리보기 계층에 대한 복제 상태
tags
목록
조각 수준 태그. 각 항목: id, title, titlePath, name, path, description
fieldTags
목록
필드 수준 태그. tags과(와) 같은 구조입니다.

예: 템플릿 액세스

(선택한) 콘텐츠 조각의 경우:

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

참조된 콘텐츠 조각 referenced-content-fragments

참조된 조각에 대한 컨텍스트 오브젝트 구조:

변수
유형
설명
hasReferencedFragments
부울
참조가 있을 때 true
referencedFragments
목록
참조된 조각 개체 배열
referencesError
부울
참조를 로드할 때 오류가 발생한 경우 true
referencesErrorMessage
문자열
referencesError이(가) true일 때 오류 메시지

참조된 조각 구조 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(서식 있는 텍스트)가 포함된 경우 필드 값에 삼중 중괄호 {{{ }}}을(를) 사용합니다.
  • 필드 이름(제목, 자막, 설명, primaryImage) 은(는) 콘텐츠 조각 모델​정확히​과(와) 일치해야 합니다.
  • 누락된 필드는 렌더링되지 않습니다. 오류가 발생하지 않으며 Handlebars 구문이 렌더링된 HTML 조각에 표시(및 표시)됩니다.

모든 필드 반복 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

다중 값을 지정하면 텍스트, number, 날짜 및 기타 단순 필드가 배열이 됩니다.

<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}}
조건이 truthy인 경우 콘텐츠를 렌더링합니다. 잘못된 값: false, undefined, null, 0, "", []
{{#unless condition}}
조건이 falsy인 경우 콘텐츠를 렌더링합니다(#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 마크업 콘텐츠가 포함된 필드 값에는 항상 3중 중괄호를 사용하십시오.

    • 필드 값은 사전 렌더링된 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}}}
중첩된 콘텐츠 조각 필드가 비어 있거나 [개체 개체]를 표시합니다.
{{{fields.author.name}}}이(가) 비어 있음
API 호출에서 하이드레이션을 사용하도록 설정하고, 필드 이름 철자를 확인하고, maxDepth이(가) 충분히 깊은지 확인하십시오.
다중 값 필드에는 첫 번째 항목만 표시됩니다.
5개 항목이 있는 배열은 하나만 렌더링합니다.
{{#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 주석 텍스트
HTML <!-- comment --> 대신 Handlebars 주석 {{! comment }} 사용
조건부 은 항상 true로 평가됩니다.
{{#if fields.enabled}}은(는) 항상 신뢰할 수 있음
참고: "false" 문자열은 Handlebars에서 truthy입니다. 실제 false, null, undefined, 0, ""[]만 거짓 같습니다.
엔티티로 렌더링하는 특수 문자
<, & 대신 &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="..."> 링크

기억하십시오.

  • 자산 필드에는 항상 3중 중괄호를 사용하십시오.
    이중 중괄호를 사용하면 이미지, 비디오 또는 링크를 렌더링하는 대신 생성된 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

시스템에서는 사용자 지정 HTML 속성을 사용하여 HTML 요소를 생성하는 사용자 지정 Handlebars 도우미를 제공합니다. 이러한 도우미를 통해 사전 렌더링된 콘텐츠에서 소스 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