我可以从HTML字符串或dom节点/元素创建一个React元素吗?

4

我正在从SharePoint检索一个HTML字符串,需要解析和修改数据,并构建一个React元素以在我的React应用程序中显示。

基本上,我有一些代码(作为字符串)返回给我,格式类似于:

"
<div>
    <div data-sp-canvasdataversion="1">This could be a header</div>
    <div data-sp-canvasdataversion="1"><img src="titleimage.jpg"></div>
    <div data-sp-canvasdataversion="1"><a href="pdfLink.pdf">This is a link to a PDF</a></div>
</div>
"

我需要遍历子元素并构建一个新的React元素,其中包含返回内容的一些部分和一些新部分,例如:
<div>
    <div data-sp-canvasdataversion="1">This could be a header</div>
    <div data-sp-canvasdataversion="1"><img src="titleimage.jpg"></div>
    <PDFViewer file={""pdfLink.pdf""}></PDFViewer> 
</div>

我最初使用的是dangerouslySetInnerHTML来简单显示数据,但现在我需要删除一段HTML代码,基于该数据创建一个React元素,并将新元素注入回代码中。由于我现在尝试插入一个组件,因此纯HTML不能工作。

我可以通过将其转换为DOM节点来循环遍历子节点,但我无法弄清如何将DOM节点或元素用作React元素子级。

我已经尝试过:

let element = React.createElement('div', {}, HTMLString); 

let node = document.createRange().createContextualFragment(HTMLString).firstChild;

let element = React.createElement('div', {}, node); 

let node = document.createRange().createContextualFragment(HTMLString).firstChild;
let node2 = document.createElement("div");
node2.appendChild(node);
node2 = node2.firstElementChild as HTMLDivElement;

let element = React.createElement('div', {}, node2); 

没有一个能按照需要工作并给我错误提示对象无法作为React子级(发现:[object HTMLDivElement])或类似的错误。

我需要的是像这样的东西:

let element = React.createElement('div'); 
let node = document.createRange().createContextualFragment(HTMLString).firstChild;

node.childNodes.forEach(child => {
    if(...//child IS NOT pdf)
        element.appendChild(child)
    else if(...//child IS pdf){
        ...
        element.appendChild(<PDFViewer file="linktopdf.pdf">)
    }
})

然后我希望能够在渲染中使用它。
render {
    ...
    return(
        <div className="container">
            {element}
        </div>
    );
}

请告诉我这是否有可能,以及如何实现。我能想到的唯一可能的解决方案是将子元素保存为字符串,然后使用dangerouslySetInnerHTML生成它们,但我真的不想使用dangerouslySetInnerHTML,特别是像这样的方式。

你可以尝试使用react-html-parser https://www.npmjs.com/package/react-html-parser将HTML转换成React组件,然后用于你的目的。 - Rikin
1
不确定解析,但是当您想在React中将字符串呈现为原始的HTML时,唯一可用的API是dangerouslySetInnerHTML - Sagiv b.g
在文档中查看react-hyperscript的示例。如果您愿意,可以使用该库,或者只需使用相同的思路从头开始实现它,因为您已经能够将它们转换为DOM节点了。 - marsheth
2个回答

4
针对React v17.0以下版本,请尝试使用react-html-parser
针对React v17.0及以上版本,请尝试使用fork(感谢@thesdev指出)。

不支持React 17+,请查看此分支https://github.com/hedgedoc/html-to-react。 - thesdev

3

我最终使用了dangerouslySetInnerHTML,这不是我想要的。如果有人有更好的解决方案,请随时分享。

async getArticleComponents(data: any) {
    if (!data)
        return null;

    let slides = []
    let node = document.createRange().createContextualFragment(data).firstChild;
    let children = node.childNodes;

    for (let i = 0; i < children.length; i++) {
        var element = (children[i] as HTMLDivElement);
        var controlElement = element.attributes.getNamedItem("data-sp-controldata");
        var jObj = controlElement ? JSON.parse(controlElement.value) : null;

        if (jObj.controlType === 3) {
            var childEle = element.firstElementChild;
            var webPartData = childEle.attributes.getNamedItem("data-sp-webpartdata");
            var wpJObj = webPartData ? JSON.parse(webPartData.value) : null;

            if (wpJObj.title == "File viewer") {
                let ext = (/.*\.(.*)/i).exec(wpJObj.properties.file)[1].toLowerCase();
                if (ext === "pdf") {
                    var pdf = await fetch(`/api/SharePoint/GetFile?url=${encodeURIComponent(`${wpJObj.serverProcessedContent.links.serverRelativeUrl}`)}`)
                    .then(res => res.text())
                    .then(pdf => pdf ? `data:application/pdf;base64,${pdf}` : null);

                    slides.push(<PDFViewer key={jObj.id} file={{ pdf, fileName: "test" } as IPdfMeta} />);
                }
            } else
                slides.push(<div key={jObj.id} dangerouslySetInnerHTML={{ __html: element.outerHTML }}></div>);
        }
        else if (jObj.controlType !== 0) {
            slides.push(<div key={jObj.id} dangerouslySetInnerHTML={{ __html: element.outerHTML }}></div>);
        }
    }
    return slides;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接