AEM Headless多信息文本

多行文本字段是内容片段的数据类型,它允许作者创建富文本内容。 对其他内容(如图像或其他内容片段)的引用可以动态地内嵌在文本流中。 单行文本字段是内容片段的另一种数据类型,应当用于简单文本元素。

AEM的GraphQL API提供了一项强大的功能,可将RTF作为HTML、纯文本或纯JSON返回。 JSON表示法非常强大,因为它使客户端应用程序可以完全控制如何呈现内容。

多行编辑器

在内容片段编辑器中,多行文本字段的菜单栏为作者提供标准的RTF格式功能,如​ bold斜体 ​和下划线。 在全屏模式下打开多行字段可启用其他格式工具,如段落文字、查找和替换、拼写检查等

NOTE
无法自定义多行编辑器中的富文本插件。

多行文本数据类型 multi-line-data-type

定义内容片段模型时,请使用​ 多行文本 ​数据类型来启用RTF创作。

多行RTF数据类型

可以配置多行字段的多个属性。

呈现为 ​属性可以设置为:

  • 文本区域 — 呈现单个多行字段
  • 多个字段 — 呈现多个多行字段

默认类型 ​可以设置为:

  • 富文本
  • Markdown
  • 纯文本

默认类型 ​选项直接影响编辑体验,并确定是否存在RTF工具。

您还可以通过检查​ 允许片段引用 ​并配置​ 允许的内容片段模型 ​来启用对其他内容片段的内联引用

如果要将内容本地化,请选中​ 可翻译 ​框。 只能本地化富文本和纯文本。 有关更多详细信息,请参阅使用本地化的内容

GraphQL API富文本响应

创建GraphQL查询时,开发人员可以从多行字段中选择来自htmlplaintextmarkdownjson的其他响应类型。

开发人员可以在内容片段编辑器中使用JSON预览来显示当前内容片段的所有值,这些值可以使用GraphQL API返回。

GraphQL持久查询

在处理富文本内容时,为多行字段选择json响应格式可提供最大的灵活性。 富文本内容以JSON节点类型数组的形式交付,可以基于客户端平台唯一处理这些类型。

以下是名为main的多行字段的JSON响应类型,该字段包含段落:“”这是一个包含​ 重要 ​内容的段落。,其中“重要”标记为​ bold

query ($path: String!) {
  articleByPath(_path: $path)
  {
    item {
      _path
      main {
        json
      }
    }
  }
}

_path筛选器中使用的$path变量需要内容片段的完整路径(例如/content/dam/wknd/en/magazine/sample-article)。

GraphQL响应:

{
  "data": {
    "articleByPath": {
      "item": {
        "_path": "/content/dam/wknd/en/magazine/sample-article",
        "main": {
          "json": [
            {
              "nodeType": "paragraph",
              "content": [
                {
                  "nodeType": "text",
                  "value": "This is a paragraph that includes "
                },
                {
                  "nodeType": "text",
                  "value": "important",
                  "format": {
                    "variants": [
                      "bold"
                    ]
                  }
                },
                {
                  "nodeType": "text",
                  "value": " content. "
                }
              ]
            }
          ]
        }
      }
    }
  }
}

其他示例

以下是名为main的多行字段的响应类型的几个示例,该字段包含段落:“这是一个包含​ 重要 ​内容的段落。” 其中,“重要”标记为​ bold

HTML示例

GraphQL持久查询:

code language-graphql
query ($path: String!) {
  articleByPath(_path: $path)
  {
    item {
      _path
      main {
        html
      }
    }
  }
}

GraphQL响应:

code language-json
{
  "data": {
    "articleByPath": {
      "item": {
        "_path": "/content/dam/wknd/en/magazine/sample-article",
        "main": {
            "html": "<p>This is a paragraph that includes <b>important</b> content.&nbsp;</p>\n"
        }
      }
    }
  }
}
Markdown示例

GraphQL持久查询:

code language-graphql
query ($path: String!) {
  articleByPath(_path: $path)
  {
    item {
      _path
      main {
        markdown
      }
    }
  }
}

GraphQL响应:

code language-json
{
  "data": {
    "articleByPath": {
      "item": {
        "_path": "/content/dam/wknd/en/magazine/sample-article",
        "main": {
            "markdown": "This is a paragraph that includes **important** content. \n\n ",
        }
      }
    }
  }
}
纯文本示例

GraphQL持久查询:

code language-graphql
query ($path: String!) {
  articleByPath(_path: $path)
  {
    item {
      _path
      main {
        plaintext
      }
    }
  }
}

GraphQL响应:

code language-json
{
  "data": {
    "articleByPath": {
      "item": {
        "_path": "/content/dam/wknd/en/magazine/sample-article",
        "main": {
            "plaintext": "This is a paragraph that includes important content. ",
        }
      }
    }
  }
}

plaintext渲染选项会去除任何格式。

呈现富文本JSON响应 render-multiline-json-richtext

多行字段的富文本JSON响应被构造为分层树。 每个对象或节点表示富文本的不同HTML块。

以下是多行文本字段的JSON响应示例。 请注意,每个对象或节点都包含一个nodeType,它表示富文本(如paragraphlinktext)中的HTML块。 每个节点可选地包含content,它是一个包含当前节点的任何子节点的子数组。

"json": [// root "content" or child nodes
            {
                "nodeType": "paragraph", // node for a paragraph
                "content": [ // children of current node
                {
                    "nodeType": "text", // node for a text
                    "value": "This is the first paragraph. "
                },
                {
                    "nodeType": "link",
                    "data": {
                        "href": "http://www.adobe.com"
                    },
                    "value": "An external link"
                }
                ],
            },
            {
                "nodeType": "paragraph",
                "content": [
                {
                    "nodeType": "text",
                    "value": "This is the second paragraph."
                },
                ],
            },
]

呈现多行json响应的最简单方法是处理响应中的每个对象或节点,然后处理当前节点的任何子节点。 递归函数可用于遍历JSON树。

以下是说明递归遍历方法的示例代码。 这些示例基于JavaScript并使用React的JSX,但编程概念可以应用于任何语言。

// renderNodeList - renders a list of nodes
function renderNodeList(childNodes) {

    if(!childNodes) {
        // null check
        return null;
    }

    return childNodes.map(node, index) => {
        return renderNode(node);
    }
}

renderNodeList是一个递归函数,它采用childNodes的数组。 数组中的每个节点随后都会传递到函数renderNode,如果节点具有子节点,则函数会调用renderNodeList

// renderNode - renders an individual node
function renderNode(node) {

    // if the current node has children, recursively process them
    const children = node.content ? renderNodeList(node.content) : null;

    // use a map to render the current node based on its nodeType
    return nodeMap[node.nodeType]?.(node, children);
}

renderNode函数需要一个名为node的对象。 节点可以具有使用上述renderNodeList函数递归处理的子节点。 最后,nodeMap用于根据其nodeType呈现节点的内容。

// nodeMap - object literal that maps a JSX response based on a given key (nodeType)
const nodeMap = {
    'paragraph': (node, children) => <p>{children}</p>,
    'link': node => <a href={node.data.href} target={node.data.target}>{node.value}</a>,
    'text': node => node.value,
    'unordered-list': (node, children) => <ul>{children}</ul>,
    'ordered-list': (node, children) => <ol>{children}</ol>,
    'list-item': (node, children) => <li>{children}</li>,
    ...
}

nodeMap是用作映射的JavaScript对象文字。 每个“键”代表不同的nodeTypenodechildren的参数可以传递到渲染节点的生成函数。 此示例中使用的返回类型是JSX,但该方法可以适用于构建表示HTML内容的字符串文字。

完整代码示例

可在WKND GraphQL React示例中找到可重用的富文本渲染实用程序。

  • renderRichText.js — 可重用实用程序,该实用程序公开函数mapJsonRichText。 此实用程序可供希望将富文本JSON响应渲染为React JSX的组件使用。
  • AdventureDetail.js — 发出包含富文本的GraphQL请求的组件示例。 组件使用mapJsonRichText实用程序呈现富文本和任何引用。

添加对富文本的内联引用 insert-fragment-references

利用多行字段,作者可以在富文本流中插入来自AEM Assets的图像或其他数字资产。

插入图像

上面的屏幕快照描述了使用​ 插入资源 ​按钮在多行字段中插入的图像。

也可以使用​ 插入内容片段 ​按钮在多行字段中链接或插入对其他内容片段的引用。

插入内容片段引用

上面的屏幕截图描述了另一个内容片段,洛杉矶滑板公园终极指南,插入多行字段中。 可插入到字段中的内容片段的类型由内容片段模型中多行数据类型中的​ 允许的内容片段模型 ​配置控制。

使用GraphQL查询内联引用

GraphQL API允许开发人员创建查询,查询中包含有关插入到多行字段中的任何引用的其他属性。 JSON响应包含一个单独的_references对象,其中列出了这些额外的属性。 JSON响应使开发人员能够完全控制如何呈现引用或链接,而不必处理教条式HTML。

例如,您可能希望:

  • 包含自定义路由逻辑,用于在实施单页应用程序(如使用React Router或Next.js)时管理指向其他内容片段的链接
  • 使用指向AEM Publish环境的绝对路径作为src值渲染内嵌图像。
  • 确定如何使用其他自定义属性呈现对其他内容片段的嵌入引用。

构造GraphQL查询时,请使用json返回类型并包含_references对象:

GraphQL持久查询:

query ($path: String!) {
  articleByPath(_path: $path, _assetTransform: { format: JPG, preferWebp: true })
  {
    item {
      _path
      main {
        json
      }
    }
    _references {
      ...on ImageRef {
        _dynamicUrl
        __typename
      }
      ...on ArticleModel {
        _path
        author
        __typename
      }
    }
  }
}

在上述查询中,main字段返回为JSON。 _references对象包含用于处理任何类型为ImageRef或类型为ArticleModel的引用的片段。

JSON响应:

{
  "data": {
    "articleByPath": {
      "item": {
        "_path": "/content/dam/wknd/en/magazine/sample-article",
        "main": {
          "json": [
            {
              "nodeType": "paragraph",
              "content": [
                {
                  "nodeType": "text",
                  "value": "This is a paragraph that includes "
                },
                {
                  "nodeType": "text",
                  "value": "important",
                  "format": {
                    "variants": [
                      "bold"
                    ]
                  }
                },
                {
                  "nodeType": "text",
                  "value": " content. "
                }
              ]
            },
            {
              "nodeType": "paragraph",
              "content": [
                {
                  "nodeType": "reference",
                  "data": {
                    "path": "/content/dam/wknd/en/activities/climbing/sport-climbing.jpg",
                    "mimetype": "image/jpeg"
                  }
                }
              ]
            },
            {
              "nodeType": "paragraph",
              "content": [
                {
                  "nodeType": "text",
                  "value": "Reference another Content Fragment: "
                },
                {
                  "nodeType": "reference",
                  "data": {
                    "href": "/content/dam/wknd/en/magazine/la-skateparks/ultimate-guide-to-la-skateparks",
                    "type": "fragment"
                  },
                  "value": "Ultimate Guide to LA Skateparks"
                }
              ]
            }
          ]
        }
      },
      "_references": [
        {
          "_dynamicUrl": "/adobe/dynamicmedia/deliver/dm-aid--dd42d814-88ec-4c4d-b5ef-e3dc4bc0cb42/sport-climbing.jpg?preferwebp=true",
          "__typename": "ImageRef"
        },
        {
          "_path": "/content/dam/wknd/en/magazine/la-skateparks/ultimate-guide-to-la-skateparks",
          "author": "Stacey Roswells",
          "__typename": "ArticleModel"
        }
      ]
    }
  }
}

JSON响应包括引用插入到带"nodeType": "reference"的富文本中的位置。 然后,_references对象包含每个引用。

以富文本呈现内联引用

要呈现内联引用,可以展开呈现多行JSON响应中说明的递归方法。

其中nodeMap是渲染JSON节点的映射。

const nodeMap = {
        'reference': (node, children) => {

            // variable for reference in _references object
            let reference;

            // asset reference
            if (node.data.path) {
                // find reference based on path
                reference = references.find( ref => ref._path === node.data.path);
            }
            // Fragment Reference
            if (node.data.href) {
                // find in-line reference within _references array based on href and _path properties
                reference = references.find( ref => ref._path === node.data.href);
            }

            // if reference found, merge properties of reference and current node, then return render method of it using __typename property
            return reference ? renderReference[reference.__typename]({...reference, ...node}) : null;
        }
    }

高级方法是每当nodeType等于Mutli Line JSON响应中的reference时进行检查。 然后,可以调用一个自定义渲染函数,该函数包含在GraphQL响应中返回的_references对象。

然后,可以将内联引用路径与_references对象中的相应条目进行比较,并且可以调用另一个自定义映射renderReference

const renderReference = {
    // node contains merged properties of the in-line reference and _references object
    'ImageRef': (node) => {
        // when __typename === ImageRef
        return <img src={node._dynamicUrl} alt={'in-line reference'} />
    },
    'ArticleModel': (node) => {
        // when __typename === ArticleModel
        return <Link to={`/article:${node._path}`}>{`${node.value}`}</Link>;
    }
    ...
}

_references对象的__typename可用于将不同的引用类型映射到不同的渲染函数。

完整代码示例

AdventureDetail.js中可以找到编写自定义引用渲染器的完整示例,它是WKND GraphQL React示例的一部分。

端到端示例

NOTE
上述视频使用_publishUrl渲染图像引用。 相反,首选使用_dynamicUrl,如网络优化图像how-to中所述;

前面的视频展示了一个端到端示例:

  1. 更新内容片段模型的多行文本字段以允许片段引用
  2. 使用内容片段编辑器在多行文本字段中包含图像和对其他片段的引用。
  3. 创建一个GraphQL查询,该查询包括作为JSON的多行文本响应以及使用的任何_references
  4. 编写React SPA以呈现富文本响应的内联引用。
recommendation-more-help
e25b6834-e87f-4ff3-ba56-4cd16cdfdec4