可视化内容片段 — 随发布URL一起提供 visual-content-fragments-deliver-with-the-publish-url

发布基于附加HTML模板的模型的内容片段时,该片段的渲染的HTML可通过以下结构的URL中的Adobe Experience Manager (AEM) as a Cloud Service发布层使用:

https://publish-p<programId>-e<envId>.adobeaemcloud.com/adobe/stable/previewtemplates/contentFragments/<templateId>/<fragmentId>/<variation>.html

此URL返回可嵌入到任何Web上下文中的​自包含HTML文档(包括内联CSS和结构)。

嵌入技术 — 概述 embedding-techniques-overview

可通过三种不同方法从主机页面上的可视内容片段使用HTML。 每个页面都具有风格隔离、布局行为、可访问性和复杂性的独特特性。

内联元素
iframe
自定义元素+阴影DOM
机制
fetch() URL,通过innerHTML将响应HTML插入<div>
<iframe src="publishURL">
定义一个自定义元素fetch() HTML,将其注入连接的影子DOM根中
样式隔离
无 — 片段CSS泄漏到主机页面,主机CSS影响片段
完整 — 单独的浏览上下文,完成CSS隔离
强 — 阴影DOM边界块主机CSS层叠;片段样式保持封装状态
布局参与率
完整 — 内容是正常文档流的一部分,响应Flexbox/网格/容器大小调整
无 — iframe具有固定维度;需要明确的width/height或基于JS的自动调整大小
完整 — 自定义元素与任何其他DOM元素一样,参与主机文档的正常流
辅助功能(a11y)
最佳 — 内容位于主DOM树中,可通过屏幕阅读器和辅助技术完全遍历
审核 — 单独的浏览上下文可能会混淆屏幕阅读器导航;需要title属性
良好 — 内容位于同一文档中;影子DOM可通过现代辅助技术遍历
SEO
差 — 通过JS fetch()加载的内容未被大多数爬虫编入索引
差 — iframe内容通常不会在父页面上下文中编制索引
差 — 与内联相同;JS获取的内容不可爬网
JavaScript运行时
共享 — 相同的窗口/文档上下文;如果片段包含<script>标记,则存在脚本冲突风险
隔离 — 单独的窗口上下文;无冲突风险
共享 — 相同的窗口上下文但DOM范围相同;影子根目录中的脚本在主机上下文中执行
跨源支持
发布URL上需要CORS标头(服务会配置这些标头)
原生工作 — iframe加载跨源内容而不使用CORS
发布URL上需要CORS标头(与内联标头相同)
实施复杂性
最小 — 几行JS
普通 — 无需任何JS;纯HTML
低 — 约20行用于自定义元素定义的JS,可跨页面重用
最适合
原型构建、受信任的同源内容、布局集成至关重要的上下文以及CSS冲突可管理
快速嵌入、沙盒内容、CORS不可用的跨源方案、必须完全隔离的内容
生产使用 — 平衡隔离、布局参与和可访问性(建议用于AEM核心组件和外部站点)

内联元素(fetch + innerHTML) inline-element-fetch-and-innerhtml

最简单的方法:

  1. 获取发布URL
  2. 将HTML注入容器元素

内联元素嵌入示例:

<div id="cf-container"></div>
<script>
  fetch("<publish-url>")
    .then(r => r.ok ? r.text() : Promise.reject(r.status))
    .then(html => {
      document.getElementById("cf-container").innerHTML = html;
    })
    .catch(err => console.error("Failed to load fragment", err));
</script>

何时使用:

  • 快速原型制作或概念验证页面
  • 用于控制主机页面和片段样式的同域上下文
  • 当最大布局灵活性比样式封装更重要时
CAUTION
CSS冲突风险
片段的内联样式(包括其<style>块、字体声明和元素选择器)合并到主机页面的层叠中。
这可能导致两个方向都出现意外的样式覆盖。
只有在可以容忍或主动管理这些冲突时才使用此技术。

iframe iframe

直接将发布URL作为<iframe>src加载。 不需要JavaScript。

iframe嵌入示例:

<iframe
  src="<publish-url>"
  title="Content Fragment Preview"
  width="100%"
  height="600"
  frameborder="0"
  style="border: none;"
></iframe>

您还可以自动调整iframe的大小(这是可选的)。

要动态地将iframe调整到其内容高度(避免使用滚动条),请使用postMessage模式或适当的库。

轻量化方法的一个示例是:

<iframe id="cf-iframe" src="<publish-url>" title="Content Fragment Preview"
  width="100%" frameborder="0" style="border:none; overflow:hidden;"
  onload="this.style.height = this.contentDocument.documentElement.scrollHeight + 'px';"
></iframe>
WARNING
上述onload自动调整大小方法仅适用于​相同原点 iframe。
对于​ 跨源 ​发布URL,您需要基于postMessage的解决方案或设置固定高度。

何时使用:

  • Edge Delivery Services嵌入块(默认集成 — 请参阅以下部分)
  • 完整CSS/JS隔离很重要的上下文
  • 未配置CORS的跨源嵌入
  • 零代码快速集成(只需粘贴URL)

定义一个可重复使用的<cf-visualization>自定义元素,用于获取发布URL并将HTML注入到封装的影子DOM根中。

此元素提供:

  • 阴影DOM隔离
    • 片段的标记和样式将封装在影子根中,从而防止与主机页面的CSS层叠发生冲突。
  • 内联布局参与率
    • 呈现的内容参与主机文档的正常流,响应容器大小调整和Flexbox/Grid上下文,无需手动维度管理。
  • 单个浏览上下文
    • 不创建辅助文档上下文;片段内容共享页面的JavaScript运行时,并且可由辅助技术完全遍历。
  • 最小开销
    • 单个fetch调用从发布层检索预渲染的HTML。 无需客户端渲染框架。
IMPORTANT
这是推荐用于生产的方法,也是AEM核心组件使用的技术。

要定义自定义元素,请每页包含一次以下脚本。 该页面上的所有<cf-visualization>实例都将使用此定义:

<script>
  class CfVisualization extends HTMLElement {
    connectedCallback() {
      const src = this.getAttribute("src");
      if (!src) return;

      const shadow = this.attachShadow({ mode: "open" });

      fetch(src)
        .then((r) => (r.ok ? r.text() : Promise.reject(r.status)))
        .then((html) => {
          shadow.innerHTML = html;
        })
        .catch((err) => {
          console.error("cf-visualization: failed to load", src, err);
        });
    }
  }

  if (!customElements.get("cf-visualization")) {
    customElements.define("cf-visualization", CfVisualization);
  }
</script>

要使用自定义元素,请执行以下操作:

<cf-visualization src="<publish-url>"></cf-visualization>

何时使用:

  • 使用核心组件的AEM Sites页面(这是内置行为)
  • 需要干净且可重复使用的集成的外部/第三方网站
  • 需要样式隔离和布局流参与的任何上下文

与Edge Delivery Services(嵌入块)集成 integration-with-edge-services-embed-block

在Edge Delivery Services中,发布URL通过​ 嵌入块 ​使用,这会将其呈现为<iframe>

  1. 确保项目中存在Embed块。

    如果您的EDS项目尚未包含嵌入块,请从aem-block-collection存储库复制该块:

    code language-cmdline
    # From the aem-block-collection repo, copy blocks/embed/ into your project's blocks/ directory
    cp -r aem-block-collection/blocks/embed/ your-eds-project/blocks/embed/
    
  2. 在文档创作编辑器中创作嵌入(在Edge Delivery Services中)

    在文档创作中,块以表形式表示。 要添加可视化内容片段嵌入,请执行以下操作:

    table 0-row-1 1-row-1
    嵌入
    (将发布URL粘贴为超链接)

    或者,如果您的项目或Sidekick在其块库中配置了嵌入块,则可以通过斜杠菜单插入该嵌入块,并将发布URL粘贴到块内容中。

  3. 结果

    嵌入块呈现<iframe>中的发布URL。 片段内容在EDS页面布局中以完整的CSS隔离方式加载。

集成 — AEM Sites与核心组件 integration-aem-sites-with-core-components

内容片段核心组件(core/wcm/components/contentfragment/v1/contentfragment)已内置对使用客户元素+影子DOM技术呈现可视化内容片段的支持。

工作原理:

  • 创作模式:

    当组件的displayMode设置为vcf时,创作clientlib (vcfRenderer.js)从预览API中提取片段HTML并将其内联渲染到创作画布中。

    例如,“作者”预览端点为:

    code language-html
    GET /adobe/sites/cf/fragments/{fragmentId}/preview?templateId={templateId}&variation={variation}
    
  • 发布模式:

    在发布的页面(wcmmode.disabled)上,HTL模板呈现一个内联脚本,该脚本从发布URL中提取并将HTML注入影子DOM根中。

    示例核心组件可视化内容片段(templates.html):

    code language-html
    <div class="cmp-contentfragment cmp-contentfragment--vcf"
       data-cmp-contentfragment-id="{fragmentId}"
       data-cmp-contentfragment-vcf-template="{templateId}"
       data-cmp-contentfragment-variation="{variation}">
      <!-- Only rendered when wcmmode.disabled (publish) -->
      <div data-vcf-url="{vcfPublishUrl}" class="cmp-contentfragment__vcf-loader" style="display:none"></div>
      <script>
          (function() {
              var script = document.currentScript;
              var loader = script.previousElementSibling;
              var el = script.parentElement;
              if (!el || !loader) return;
              var url = loader.dataset.vcfUrl;
              if (!url) return;
              loader.remove();
              var shadow = el.attachShadow({ mode: "open" });
              var body = document.createElement("body");
              body.style.display = "none";
              shadow.appendChild(body);
              fetch(url)
                  .then(function(r) { return r.ok ? r.text() : Promise.reject(r.status); })
                  .then(function(html) {
                      body.innerHTML = html;
                      body.style.display = "";
                  });
          })();
      </script>
    </div>
    

    发布URL格式:

    Sling模型(ContentFragmentImpl)使用以下模式构建发布URL:

    code language-html
    /adobe/experimental/previewtemplates-expires-20260301/contentFragments/{templateId}/{fragmentId}/{variation}.html
    

    运行时将针对发布主机解析此相对URL。

与外部站点集成 integration-with-external-sites

对于非AEM网站,请使用Customer Element + Shadow DOM技术。 这为您提供了干净的声明性集成,而无需依赖框架。

示例为:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Product Page</title>
</head>
<body>
  <h1>Product Details</h1>
  <p>Some host-page content here...</p>

  <!-- Embed the Content Fragment visualization -->
  <cf-visualization
    src="https://publish-p12345-e67890.adobeaemcloud.com/adobe/experimental/previewtemplates-expires-20260301/contentFragments/product_template/abc-123/master.html"
  ></cf-visualization>

  <p>More host-page content below the fragment...</p>

  <!-- Custom Element definition (include once) -->
  <script>
    class CfVisualization extends HTMLElement {
      connectedCallback() {
        const src = this.getAttribute("src");
        if (!src) return;
        const shadow = this.attachShadow({ mode: "open" });
        fetch(src)
          .then(r => r.ok ? r.text() : Promise.reject(r.status))
          .then(html => { shadow.innerHTML = html; })
          .catch(err => console.error("cf-visualization: failed to load", src, err));
      }
    }
    if (!customElements.get("cf-visualization")) {
      customElements.define("cf-visualization", CfVisualization);
    }
  </script>
</body>
</html>
NOTE
您可以将多个<cf-visualization>元素放置到具有不同src URL的同一页面上。 自定义元素定义只需包含一次。

CORS和安全注意事项 cors-and-security-considerations

关注
详细信息
CORS
内容片段可视化服务使用可配置的允许源在/adobe/**路径上配置CORS。
Inline Element (撷取+ innerHTML)🔗 1和Customer Element + Shadow DOM技术(使用fetch())要求主机页面的原点位于允许列表中。
iFrame技术不需要CORS。
CSP/X-Frame-Options
该服务未在发布的HTML上设置Content-Security-PolicyX-Frame-Options标头。 如果您的CDN或Dispatcher添加了这些标头,请验证它们是否允许从您的主机源进行成帧(对于iFrame)或fetch()访问(对于内联/影子DOM)。
内容信任
使用由服务管理的Handlebars模板,从创作的内容片段数据中预呈现已发布的HTML。 它不包括用户生成的脚本。 但是,与任何innerHTML注入一样,请确保信任源来源。

选择适当的技术 choose-the-appropriate-technique

使用下列内容作为决策指南,帮助您选择适当的技术:

场景
解决办法
需要零JavaScript和完全隔离?
Iframe
需要通过样式隔离来参与布局流吗?
自定义元素+影子DOM(推荐)
是否可接受最快的原型、相同来源和CSS冲突?
内联元素
是否嵌入到Edge Delivery Services?
嵌入块(外壳下的iframe)
是否嵌入到AEM Sites页面?
核心组件(影子DOM,内置)

其他资源 additional-resources

其他资源可供使用:

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