JSX 组件 + 危险的 SetInnerHTML?

Posted

技术标签:

【中文标题】JSX 组件 + 危险的 SetInnerHTML?【英文标题】:JSX Component + dangerouslySetInnerHTML? 【发布时间】:2018-04-30 19:17:25 【问题描述】:

所以我在实现这个场景时遇到了麻烦:

从后端服务器,我收到一个 html 字符串,如下所示:

<ul><li><strong>Title1</strong> <br/> <a class=\"title1" href="title1-link">Title 1</a></li><li><strong>Title2</strong> <a class="title2" href="/title2-link">Title 2</a>

通常,只使用dangerouslySetInnerHTML 就可以了。

但是,围绕 html 中的 a href 标签,我需要将它们包装在组件中,如下所示:

<ModalLink href='title'>
    Title
</ModalLink>

这是因为在包装a 标签时,组件本质上添加了创建新子窗口的功能。

我认为这是你需要在 Regex 上实现的东西,但我不知道从哪里开始。

【问题讨论】:

【参考方案1】:

您可以使用正则表达式从您的 html 字符串中解构和提取必要的值,然后使用 JSX 代替危险的SetInnerHtml。该组件展示了如何呈现您的示例 html 字符串。

import React,  Component  from 'react'

export default class App extends Component 
    render() 
        const html = `<ul><li><strong>Title1</strong><br/><a class="title1" href="/title1-link">Title 1</a></li><li><strong>Title2</strong><br/><a class="title2" href="/title2-link">Title 2</a></li></ul>`

        return (
            <div>
                <ul>
                html.match(/(<li>.*?<\/li>)/g).map( li => 
                    const title =  li.match(/<strong>(.*?)<\/strong>/)[1]
                    const aTag = li.match(/<a.*?\/a>/)[0]
                    const aClass = aTag.match(/class="(.*?)"/)[1]
                    const href = aTag.match(/href="(.*?)"/)[1]
                    const aText = aTag.match(/>(.*?)</)[1]
                    return (
                        <li>
                            <strong>title</strong>
                            <br/>
                            <a className=aClass href=href>aText</a>
                        </li>
                    )
                )
                </ul>
            </div>
        )
    

从那里您可以简单地将 a 标签包装在您的 ModalLink 组件中。我不确定这正是您想要的方式,但这里有一个示例。

return ( 
    <li>
        <strong>title</strong>
        <br/>
        <ModalLink href=href>
            <a className=aClass href=href>aText</a>
        </ModalLink>
    </li>
)

html.match(/(&lt;li&gt;.*?&lt;\/li&gt;)/g) 匹配数组中 html 字符串中的每个 &lt;li&gt;...&lt;/li&gt;,然后可以映射。然后我使用捕获(括号内的部分)从每个&lt;li&gt;...&lt;/li&gt; 中提取标题、href 等,然后可以在 JSX 中使用。 This answer 提供了有关使用的正则表达式的更多详细信息。

【讨论】:

【参考方案2】:

不幸的是,我从未真正使用过 javascript,这就是为什么我的答案将只关注这个问题的正则表达式部分。 (不过,我在底部添加了一个尝试!)

如果我理解正确,您想用&lt;ModalLink href='someLink'&gt;someTitle&lt;/ModalLink&gt; 替换&lt;a href="someLink"&gt;someTitle&lt;/a&gt; 标记,使someLinksomeTitle 也出现在ModalLink 标记中 - 请纠正我我以错误的方式理解这一点

现在看看这里的正则表达式模式

<a [^<]+?href\s*=\s*("|')(.*?)\1>(.*?)<\/a>

它将匹配以&lt;a 开头的任何标记并匹配所有字符,直到找到href(在href 和等式标记之间有任意数量的空格)。然后它将搜索''"" 引号之间的字符串并捕获它以便以后使用。它再次匹配,直到找到标记 &gt; 的结尾并捕获该结尾和结束标记 &lt;\a&gt; 之间的任何内容。

如果您现在使用某种方法来替换给定字符串中匹配的正则表达式(很抱歉,我不熟悉这在 JavaScript 中的工作方式)并用此模式替换它

<ModalLink href='$2'> $3 </ModalLink>

对于您收到的示例 html 字符串,您将得到如下结果:

<ul><li><strong>Title1</strong> <br/> <ModalLink href='title1-link'> Title 1 </ModalLink></li><li><strong>Title2</strong> <ModalLink href='/title2-link'> Title 2 </ModalLink>

替换模式的 $2 和 $3 部分是前面提到的捕获部分的占位符,如您所见,它们将被它们替换。 (他们正在捕获第 2 组和第 3 组,而不是从 1 开始,因为我已经将引号捕获为捕获第 1 组)

你可以试试我提供的模式here。

虽然您可以在窗口上部查看和编辑正则表达式和字符串输入,但在下部可以找到替换模式及其结果。


编辑:我现在已经尽力使用在线编译器来使用 JavaScript 方法将标签替换为标签,并且在使用上述正则表达式的这种方法时似乎可以正常工作:

var regexMatch = html.replace(/<a [^<>]+?href\s*=\s*("|')(.*?)\1[^<>]*?>(.*?)<\/a>/g, "<ModalLink href='$2'> $3 </ModalLink>");

在这种情况下,html 当然应该是要替换 &lt;a&gt; 标记的 html 字符串。

你也可以试试this online here。

【讨论】:

以上是关于JSX 组件 + 危险的 SetInnerHTML?的主要内容,如果未能解决你的问题,请参考以下文章

在没有危险的SetInnerHTML的情况下在字符串上添加标记

替代危险的SetInnerHTML

使用危险的SetInnerHTML 执行脚本

如何危险地使用SetInnerHTML

React JS如何在危险的SetInnerHTML中执行脚本

如何在反应中添加 target=_blank