Ao trabalhar com o Astro.js e a API de entrega sem cabeça do Umbraco, um desafio que os programadores podem enfrentar é a renderização dinâmica de conteúdo de texto rico armazenado como JSON. Ao contrário do conteúdo HTML tradicional, que pode ser injetado utilizando set:html
, os dados JSON estruturados requerem uma abordagem mais flexível, especialmente quando é necessário integrar componentes personalizados para manipular elementos específicos.
A diretiva set:html
do Astro é uma forma comum de renderizar conteúdo HTML em bruto de forma segura. No entanto, quando se lida com JSON estruturado - como o umb-rte-element
do Umbraco - este
método torna-se limitativo. Precisamos de uma forma de analisar a estrutura JSON e renderizar dinamicamente os componentes apropriados, mantendo a arquitetura baseada em componentes do Astro.
Para lidar com isso, podemos criar um componente recursivo do Astro que processa o JSON e renderiza os elementos apropriados usando componentes do Astro. Os tipos no código a seguir foram gerados usando o pacote Umbraco.Community.DeliveryApiExtensions, que ajuda a definir tipos fortes para a resposta JSON. Ao utilizar tipagem forte e extensões da comunidade como Umbraco.Community.DeliveryApiExtensions, garantimos um tratamento mais seguro e previsível do conteúdo baseado em JSON.
Exemplo de Json:
"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
}
]
}
RichTextField.astro
---
import type { RichTextGenericElementModel , RichTextRootElementModel , RichTextTextElementModel } from"@/api/umbraco";
import {richTextFieldHasContent} from"./RichTextHelper"import RenderRichText from'./RenderRichText.astro';
interface Props {
richTextField: RichTextGenericElementModel | RichTextRootElementModel | RichTextTextElementModel | null | undefined;
}
const { richTextField } = Astro.props;
if (!richTextFieldHasContent(richTextField)) returnnull;
// If the field is the root element, grab the blocks for use in block elements.let blocks: any[] = [];
if (richTextField && richTextField.tag === '#root') {
const root = richTextField as RichTextRootElementModel;
blocks = root.blocks;
}
---
<divclass="rich-text-block container mx-auto px-[15px]"><RenderRichTextnode={richTextField}blocks={blocks}></div>
RenderRichText.astro:
---
// filepath: /src/components/richText/RenderRichText.astro
import RichTextFieldBlockItem from './RichTextFieldBlockItem.astro';
import type { ApiBlockItemModel, RichTextGenericElementModel, RichTextRootElementModel, RichTextTextElementModel } from "@/api/umbraco";
import RenderRichTextComponent from './RenderRichText.astro';
interface Props {
node: RichTextGenericElementModel | RichTextRootElementModel | RichTextTextElementModel | null | undefined;
blocks: ApiBlockItemModel[] | null | undefined;
}
const { node, blocks } = Astro.props;
if (!node) return null;
const voidElements = [
"area",
"base",
"br",
"col",
"embed",
"hr",
"img",
"input",
"link",
"meta",
"param",
"source",
"track",
"wbr"
];
const isText = node.tag === '#text';
const textNode = isText ? nodeas RichTextTextElementModel : null;
const isRoot = node.tag === '#root';
const rootNode = isRoot ? nodeas RichTextRootElementModel : null;
const isBlock = node.tag === 'umb-rte-block';
const blockNode = isBlock ? nodeas RichTextGenericElementModel : null;
const block = isBlock ? blocks?.find((b) => b.content && b.content.id === blockNode?.attributes['content-id']) : null;
const isGeneric = !isText && !isRoot && !isBlock;
const genericNode = isGeneric ? nodeas RichTextGenericElementModel : null;
const GenericTag = genericNode?.tag|| 'div';
const isVoidElement = voidElements.includes(GenericTag);
---
{isText && <Fragment set:html={textNode?.text}></Fragment>}
{isRoot && rootNode?.elements.map((child, i) =>
<RenderRichTextComponent node={child} blocks={blocks} />)}
{isBlock && <RichTextFieldBlockItem block={block} />}
{isGeneric && isVoidElement && (
<GenericTag {...genericNode?.attributes} />
)}
{isGeneric && !isVoidElement && (
<GenericTag {...genericNode?.attributes}>
{genericNode?.elements.map((child, i) =>
)}
</GenericTag>
)}
umb-rte-element
, ele passa os dados do bloco associado para um RichTextFieldBlockItem que determina o componente astro que deve renderizar o bloco.Esta abordagem dá aos desenvolvedores Astro.js que trabalham com a API Headless Delivery do Umbraco uma maneira estruturada de renderizar rich text sem depender de set:html
e permite consumir facilmente componentes astro regulares para renderização.
Se estiver a integrar a API de entrega sem cabeça do Umbraco com o Astro.js, o tratamento adequado do JSON de rich text é fundamental para uma experiência de desenvolvimento sem problemas. Com este método, pode manter uma estrutura limpa baseada em componentes enquanto renderiza conteúdo dinâmico de forma eficiente.
7 de fevereiro de 2025
6 de fevereiro de 2025
15 de agosto de 2024
A equipe da Given Data LLC monitora continuamente os avanços no espaço de gerenciamento de conteúdo, mantendo-nos à frente da concorrência. Necessidade urgente? ligue para nós