You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Astro.js中不使用set:html渲染JSON中的HTML内容

渲染CMS富文本JSON中的动态元素与Astro组件

内容管理系统(CMS)会输出包含嵌入对象的JSON格式富文本数据,我需要一套方案:既能渲染带动态属性的普通元素,又能在JSON里的嵌入对象位置渲染对应的Astro组件。

Astro的set:html指令可直接渲染HTML,但无法处理嵌入的组件,因此需要自定义实现逻辑。以下是无头CMS Umbraco输出的JSON示例(该逻辑适用于多款同类CMS):

"blogRichText": {
    "tag": "#root",
    "attributes": {},
    "elements": [
        {
            "tag": "p",
            "attributes": {
                "id": "someId",
                "class": "some-class"
            },
            "elements": [
                {
                    "text": "This is ",
                    "tag": "#text"
                },
                {
                    "tag": "strong",
                    "attributes": {},
                    "elements": [
                        {
                            "text": "bold text",
                            "tag": "#text"
                        }
                    ]
                },
                {
                    "text": " with an object following",
                    "tag": "#text"
                }
            ]
        },
        {
            "tag": "umb-rte-block",
            "attributes": {
                "content-id": "705a6633-3e20-4f3a-be76-4b450a397608"
            },
            "elements": []
        },
        {
            "tag": "p",
            "attributes": {},
            "elements": [
                {
                    "text": "with some more text",
                    "tag": "#text"
                }
            ]
        }
    ],
    "blocks": [
        {
            "content": {
                "contentType": "angularCounter",
                "id": "705a6633-3e20-4f3a-be76-4b450a397608",
                "properties": {}
            },
            "settings": null
        }
    ]
}

我尝试编写了一个动态组件来处理这种结构,原代码存在语法错误,修正后的核心组件代码如下:

---
// DynamicElement.astro
export interface Props {
  element: {
    tag: string;
    attributes?: Record<string, string>;
    elements?: Array<{ tag: string; text?: string; elements?: any[]; attributes?: any }>;
  };
  blocks?: Array<{ content: { contentType: string; id: string; properties: any } }>;
}

import AngularCounter from './AngularCounter.astro';

const { element, blocks } = Astro.props;
---

{/* 处理文本节点 */}
{element.tag === '#text' ? (
  element.text
) : element.tag === 'umb-rte-block' ? (
  {/* 处理嵌入组件:匹配对应block并渲染Astro组件 */}
  {blocks?.find(block => block.content.id === element.attributes['content-id'])?.content.contentType === 'angularCounter' && (
    <AngularCounter {...blocks.find(b => b.content.id === element.attributes['content-id'])?.content.properties} />
  )}
) : (
  {/* 处理普通HTML元素 */}
  <{element.tag} {...element.attributes}>
    {element.elements?.map(child => (
      <DynamicElement element={child} blocks={blocks} />
    ))}
  </{element.tag}>
)}

使用时,根组件可按如下方式调用:

---
import DynamicElement from './DynamicElement.astro';
// 假设从CMS获取的数据为cmsData
const { blogRichText } = cmsData;
---

{blogRichText.elements.map(element => (
  <DynamicElement key={element.tag + JSON.stringify(element.attributes)} element={element} blocks={blogRichText.blocks} />
))}

请问这套修正后的方案是否可行?


内容的提问来源于stack exchange,提问作者J Fo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 15:42:09