用React.js组件替换部分html字符串并渲染(不带dangerouslySetInnerHTML)

Replace part of html string with React.js component and render (without dangerouslySetInnerHTML)

本文关键字:串并 不带 dangerouslySetInnerHTML 字符串 字符 js React 组件 替换部 html      更新时间:2023-09-26

我正在使用Node.js/React.js客户端从WordPress API获取数据,我面临着相当棘手的问题。但希望你能帮我!:)

所以我有这种数据作为一个字符串来自WordPress API(单页内容):

"<h1>Curabitur turpis.</h1>
<p>Vestibulum purus quam, scelerisque ut, mollis sed, nonummy id, metus. Praesent blandit laoreet nibh. Aenean commodo ligula eget dolor. Donec vitae sapien ut libero venenatis faucibus.</p>
[gravityform id=&#8221;42&#8243; title=&#8221;true&#8221; description=&#8221;true&#8221;]
<h2>Donec vitae orci sed</h2>
<p><strong>Suspendisse faucibus</strong>, nunc et pellentesque egestas, lacus ante convallis tellus, vitae iaculis lacus elit id tortor. Vestibulum rutrum, mi nec elementum vehicula, eros quam gravida nisl, id fringilla neque ante vel mi.</p>
<blockquote><p>Nullam nulla eros, ultricies sit amet, nonummy id, imperdiet feugiat, pede. Aliquam lobortis. In turpis.</p></blockquote>
<ul><li>item</li><li>item</li><li>item</li></ul>"

我需要做的是将短代码[gravityform id=&#8221;42&#8243; title=&#8221;true&#8221; description=&#8221;true&#8221;]替换为React组件<GravityForm />与想要的事件处理程序等,并呈现其他html元素。

我正在做这样的替换:

export const replaceGravityFormShortcode = html => {
    if(!html) return html;
    const gravityFormRegexp = /'[gravityform id=.([0-9]{1,}).*?']/g;
    return replace(
        html,
        gravityFormRegexp,
        function (fullMatch, id) {
            return <GravityForm key={id} formId={id} />;
        }
    );
};

所以用React组件替换[shortcodes]已经覆盖了,但之后的html数据看起来像这样: [ 0:"<h1>Curabitur turpis.</h1><p>Vestibulum purus quam, scelerisque ut, mollis sed, nonummy id, metus. Praesent blandit laoreet nibh. Aenean commodo ligula eget dolor. Donec vitae sapien ut libero venenatis faucibus.</p>" 1:Object (GravityForm-component) 2:"<h2>Donec vitae orci sed</h2><p><strong>Suspendisse faucibus</strong>, nunc et pellentesque egestas, lacus ante convallis tellus, vitae iaculis lacus elit id tortor. Vestibulum rutrum, mi nec elementum vehicula, eros quam gravida nisl, id fringilla neque ante vel mi.</p><blockquote><p>Nullam nulla eros, ultricies sit amet, nonummy id, imperdiet feugiat, pede. Aliquam lobortis. In turpis.</p></blockquote><ul><li>item</li><li>item</li><li>item</li></ul>" ]

显然这在render()中不起作用因为

  1. 如果我只渲染数据表单会正常工作但所有html字符串默认都是转义的
  2. 如果我使用dangerouslySetInnerHTML,它看起来像这样(<GravityForm />[object Object])

那么对于这个问题有什么合理的解决方案吗?或者应该从不同的角度来看待这个问题?

谢谢你的帮助!


编辑

是的,你的解决方案是将html字符串更改为React Components,但它仍然不能解决html转义问题。输出还是像(截图)
<h1>Curabitur turpis.</h1><p>Vestibulum purus quam, scelerisque ut, mollis sed, nonummy id, metus. Praesent blandit laoreet nibh. Aenean commodo ligula eget dolor. Donec vitae sapien ut libero venenatis faucibus.</p>
<h2>Donec vitae orci sed</h2><p><strong>Suspendisse faucibus</strong>, nunc et pellentesque egestas, lacus ante convallis tellus, vitae iaculis lacus elit id tortor. Vestibulum rutrum, mi nec elementum vehicula, eros quam gravida nisl, id fringilla neque ante vel mi.</p><blockquote><p>Nullam nulla eros, ultricies sit amet, nonummy id, imperdiet feugiat, pede. Aliquam lobortis. In turpis.</p></blockquote><ul><li>item</li><li>item</li><li>item</li></ul>

但是,它甚至可能呈现的html没有解析html元素一个接一个从字符串?


EDIT 2 (Solution - kind of)

所以我终于找到了解决这个问题的方法。

  1. 我使用react-html-parser从数据字符串解析html元素
  2. 那么数据就像(对象是React元素): [ 0:Object 1:Object 2:"[gravityform id=”42″ title=”true” description=”true”]" 3:Object 4:Object 5:Object 6:Object ]
  3. 最后循环数据replaceGravityFormShortcodesFromArrayOfObjects(arrayOfObjects),用<GravityForm />替换[gravityform id=”42″ title=”true” description=”true”],然后渲染数据

export const replaceGravityFormShortcodesFromArrayOfObjects =(dataArray) => {
    if(!dataArray) return dataArray;
    const gravityFormRegexp = /'[gravityform id=.([0-9]{1,}).*?']/g;
    forEach(dataArray, (value, index) => {
        if(typeof value === 'string'){
            const temp = replace(
                value,
                gravityFormRegexp,
                function (fullMatch, id) {
                    return <GravityForm key={id} formId={id} />;
                }
            );
            if(temp.length === 1 && isObject(temp[0])){
                dataArray = [
                    ...dataArray.slice(0, index),
                    temp[0],
                    ...dataArray.slice(index + 1),
                ];
            }
        }
    }
    return dataArray;
};

BUT这只适用于html结构是一层深度的情况。如果"[gravityform id=”42″ title=”true” description=”true”]"是在React元素props.children,它变得棘手,我还没有找到工作的解决方案。

我遇到了完全相同的问题,下面是我的解决方案:

定义字符串:
const s = `<h1>Curabitur turpis.</h1>
<p>Vestibulum purus quam, scelerisque ut, mollis sed, nonummy id, metus. Praesent blandit laoreet nibh. Aenean commodo ligula eget dolor. Donec vitae sapien ut libero venenatis faucibus.</p>
[gravityform id=&#8221;42&#8243; title=&#8221;true&#8221; description=&#8221;true&#8221;]
<h2>Donec vitae orci sed</h2>
<p><strong>Suspendisse faucibus</strong>, nunc et pellentesque egestas, lacus ante convallis tellus, vitae iaculis lacus elit id tortor. Vestibulum rutrum, mi nec elementum vehicula, eros quam gravida nisl, id fringilla neque ante vel mi.</p>
<blockquote><p>Nullam nulla eros, ultricies sit amet, nonummy id, imperdiet feugiat, pede. Aliquam lobortis. In turpis.</p></blockquote>
<ul><li>item</li><li>item</li><li>item</li></ul>`

[*]:

拆分字符串
const normalText = s.split(/'[['s'S]+']/g)

提取id:

let ids = [];
const re = /'[gravityform id=.*([0-9]{1,}).*']/g;
s.replace(re, (fullMatch, id) => {
  ids.push(id)
})

现在数组normalTextids有我们想要连接的内容。只需将它们连接起来:

const output = normalText.map((text, index) => {
  <div>
    {text}
    <GravityForm key={ids[index]} formId={ids[index]} />
  </div>
})
// Then put `output` in the `render` function

您可能需要稍微调整一下正则表达式,因为您的字符串包含像&#8221;这样的unicode。要么先删除它们,要么先转义它们。

更新

为了不转义HTML:

<div dangerouslySetInnerHTML={{ __html: text }}/>

参考:https://facebook.github.io/react/docs/dom-elements.html