简体   繁体   English

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

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

I'm working with Node.js/React.js client that fetch data from WordPress API and I've faced quite tricky problem. 我正在使用从WordPress API获取数据的Node.js / React.js客户端,我遇到了相当棘手的问题。 But hopefully You can help me out! 但希望你可以帮助我! :) :)

So I have this kind of data as a string from WordPress API (single page content): 所以我把这种数据作为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>"

What I need to do is replace the shortcode [gravityform id=&#8221;42&#8243; title=&#8221;true&#8221; description=&#8221;true&#8221;] 我需要做的是替换短代码[gravityform id=&#8221;42&#8243; title=&#8221;true&#8221; description=&#8221;true&#8221;] [gravityform id=&#8221;42&#8243; title=&#8221;true&#8221; description=&#8221;true&#8221;] [gravityform id=&#8221;42&#8243; title=&#8221;true&#8221; description=&#8221;true&#8221;] to React component <GravityForm /> with wanted event handlers etc. and render other html elements as is. [gravityform id=&#8221;42&#8243; title=&#8221;true&#8221; description=&#8221;true&#8221;]使用想要的事件处理程序等来反应组件<GravityForm />呈现其他html元素。

I'm doing the replacing like: 我正在做的更换像:

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} />;
        }
    );
};

So replacing [shortcodes] with React components is already covered but after that the html data looks like this: [ 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>" ] 因此,已经涵盖了用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>" ]

So obviously that ain't going to work within render() because 很明显,这不会在render()工作,因为

  1. If I just render that data the form is working fine but all html strings are escaped by default 如果我只是渲染该数据表单工作正常但默认情况下所有html字符串都被转义
  2. If I use dangerouslySetInnerHTML it looks like this ( <GravityForm /> is [object Object] ) dangerouslySetInnerHTML-screenshot 如果我使用dangerouslySetInnerHTML它看起来像这样( <GravityForm />[object Object]dangerouslySetInnerHTML-screenshot

So is there any reasonable solution for this problem? 那么这个问题有什么合理的解决方案吗? Or should this be approached from some different perspective? 或者应该从不同的角度来看待这个问题?

Thanks for your help! 谢谢你的帮助!


EDIT 编辑

@joy Yes, your solution is changing the html string to React Components, but it still doesn't solve the html escape issue. @joy是的,您的解决方案是将html字符串更改为React Components,但它仍然无法解决html转义问题。 So I still have output like ( screenshot ) 所以我仍然有输出( 截图

<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>

But is it even possible to render that html without parsing the html elements one by one from the string? 但是,甚至可以在不从字符串中逐个解析html元素的情况下呈现该html吗?


EDIT 2 (Solution – kind of) 编辑2(解决方案 - 种类)

So I finally figured out ~working~ solution for this case. 所以我终于找到了〜工作〜这个案例的解决方案。

  1. I use react-html-parser to parse html elements from the data string 我使用react-html-parser来解析数据字符串中的html元素
  2. Then the data is like (Objects are React elements): [ 0:Object 1:Object 2:"[gravityform id=”42″ title=”true” description=”true”]" 3:Object 4:Object 5:Object 6:Object ] 然后数据就像(Objects is React elements): [ 0:Object 1:Object 2:"[gravityform id=”42″ title=”true” description=”true”]" 3:Object 4:Object 5:Object 6:Object ]
  3. Finally loop that data replaceGravityFormShortcodesFromArrayOfObjects(arrayOfObjects) , replace [gravityform id=”42″ title=”true” description=”true”] with <GravityForm /> and then just render the data 最后循环数据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 this works only if html structure is one level deep. 但是,这只能如果HTML结构是一个级别深度。 If "[gravityform id=”42″ title=”true” description=”true”]" is inside React element props.children , it's get trickier and I haven't figured out working solution yet. 如果"[gravityform id=”42″ title=”true” description=”true”]"在React元素props.children里面,它props.children棘手,我还没有想出工作解决方案。

I encountered exactly the same issue, and here is my solution: 我遇到了完全相同的问题,这是我的解决方案:

Define the string: 定义字符串:

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>`

Split the string by [*] : [*]拆分字符串:

const normalText = s.split(/\[[\s\S]+\]/g)

Extract the ids: 提取ID:

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

Now the arrays normalText and ids has the content we want to concatinate. 现在,数组normalTextids具有我们想要连接的内容。 Simply concat them: 简单地说:

const output = normalText.map((text, index) => {
  <div>
    {text}
    <GravityForm key={ids[index]} formId={ids[index]} />
  </div>
})

// Then put `output` in the `render` function

You may want to tune the regular expression a bit, as your string contains some unicode like &#8221; 您可能希望稍微调整正则表达式,因为您的字符串包含一些类似于&#8221;字符串&#8221; . Either remove them or escape them first. 要么删除它们要么先逃脱它们。

Update 更新

In order not to escape HTML: 为了不逃避HTML:

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM