如何在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
相关产品推荐
相关产品推荐

