【问题标题】:ReactJS convert HTML string to JSXReactJS 将 HTML 字符串转换为 JSX
【发布时间】:2013-10-16 11:13:33
【问题描述】:

我在处理 facebook 的 ReactJS 时遇到了麻烦。每当我执行 ajax 并想要显示 html 数据时,ReactJS 都会将其显示为文本。 (见下图)

通过jquery Ajax的成功回调函数显示数据。

$.ajax({
   url: url here,
   dataType: "json",
   success: function(data) {
      this.setState({
           action: data.action
      })
   }.bind(this)
});

有没有什么简单的方法可以把它转换成html?我应该如何使用 ReactJS?

【问题讨论】:

    标签: javascript jquery ajax reactjs


    【解决方案1】:

    默认情况下,React 会转义 HTML 以阻止 XSS (Cross-site scripting)。如果你真的想渲染 HTML,你可以使用dangerouslySetInnerHTML 属性:

    <td dangerouslySetInnerHTML={{__html: this.state.actions}} />
    

    React 会强制使用这种繁琐的语法,这样您就不会意外地将文本呈现为 HTML 并引入 XSS 错误。

    【讨论】:

    • 这个语法显示在主页和教程中,但我意识到它没有在其他任何地方记录,所以我只是提交了#413 来修复。
    • 正确!我已经使用 dangerouslySetInnerHTML 解决了这个问题,但是谢谢:)
    • 如果您从外部 API 获取信息,使用 dompurify npm 包中的 sanitize 函数清理内容是值得的。
    • 请注意,尽管它是“危险的”,但如果您只是使用它从您的服务器呈现 html,它并不比在网页中显示该内容更危险。如果该内容的用户提供的输入尚未经过清理,并且如果它直接来自服务器,那么您应该已经在后端进行了清理,则会出现危险。
    • 你可以试试最简单的解决方案stackoverflow.com/questions/19266197/…
    【解决方案2】:

    现在有更安全的方法来实现这一点。 docs have been updated 有这些方法。

    其他方法

    1. 最简单 - 使用 Unicode,将文件保存为 UTF-8 并将 charset 设置为 UTF-8。

      &lt;div&gt;{'First · Second'}&lt;/div&gt;

    2. 更安全 - 为 Javascript 字符串中的实体使用 Unicode 编号。

      &lt;div&gt;{'First \u00b7 Second'}&lt;/div&gt;

      &lt;div&gt;{'First ' + String.fromCharCode(183) + ' Second'}&lt;/div&gt;

    3. 或者是一个包含字符串和 JSX 元素的混合数组。

      &lt;div&gt;{['First ', &lt;span&gt;&amp;middot;&lt;/span&gt;, ' Second']}&lt;/div&gt;

    4. 不得已 - 使用 dangerouslySetInnerHTML 插入原始 HTML。

      &lt;div dangerouslySetInnerHTML={{__html: 'First &amp;middot; Second'}} /&gt;

    【讨论】:

    • 我已经准备好了文档,但是关于一个很长的 HTML 字符串,比如来自 WYSIWYG 编辑器的字符串?我看不出我们如何使用第一种、第二种或第三种方法
    • 我同意@eric。对于存储在某处的已转义内容,方法 1-3 有什么好处,例如数据库?另请注意,方法 4(唯一的方法)意味着您不能添加子节点。
    • 是的。这些带有硬编码“动态”内容的示例没有多大意义。
    • 这是我的 innerHTML -“显示管理员 \u003cb\u003e1\u0026nbsp;-\u0026nbsp;10\u003c/b\u003e of \u003cb\u003e13\u003c/b\u003e 总共”而这是正在呈现的内容 - “显示管理员 1 - 1013 个”。当我尝试使用 dangerouslySetInnerHTML 时,一切都会中断。
    【解决方案3】:

    我建议使用由milesj 创建的Interweave。它是一个了不起的库,它利用了许多巧妙的技术来解析 HTML 并将其安全地插入 DOM。

    Interweave 是一个用于安全渲染 HTML、过滤器的反应库 属性,使用匹配器自动换行文本,渲染表情符号字符,以及 更多。

    • Interweave 是一个强大的 React 库,它可以:
      • 无需使用 dangerouslySetInnerHTML 即可安全呈现 HTML。
      • 安全地去除 HTML 标签。
      • 自动 XSS 和注入保护。
      • 使用过滤器清理 HTML 属性。
      • 使用匹配器插入组件。
      • 自动链接 URL、IP、电子邮件和主题标签。
      • 渲染表情符号和表情符号字符。
      • 还有更多!

    用法示例:

    import React from 'react';
    import { Markup } from 'interweave';
    
    const articleContent = "<p><b>Lorem ipsum dolor laboriosam.</b> </p><p>Facere debitis impedit doloremque eveniet eligendi reiciendis <u>ratione obcaecati repellendus</u> culpa? Blanditiis enim cum tenetur non rem, atque, earum quis, reprehenderit accusantium iure quas beatae.</p><p>Lorem ipsum dolor sit amet <a href='#testLink'>this is a link, click me</a> Sunt ducimus corrupti? Eveniet velit numquam deleniti, delectus  <ol><li>reiciendis ratione obcaecati</li><li>repellendus culpa? Blanditiis enim</li><li>cum tenetur non rem, atque, earum quis,</li></ol>reprehenderit accusantium iure quas beatae.</p>"
    
    <Markup content={articleContent} /> // this will take the articleContent string and convert it to HTML markup. See: https://milesj.gitbook.io/interweave
    
    
    //to install package using npm, execute the command
    npm install interweave
    

    【讨论】:

    • 能否提供一个使用示例?
    • @ElAnonimo 我添加了一个使用示例。希望这能让事情更清楚一点。
    • 感谢一百万,交织正是我所需要的。干杯。
    • 这方面的文档没有帮助。此外,我尝试了几行 html,并且我的页面充满了错误消息。有人有示例或任何文档资源吗?
    • 您知道 Interweave 不涵盖哪些威胁吗?
    【解决方案4】:
    npm i html-react-parser;
    
    import Parser from 'html-react-parser';
    
    <td>{Parser(this.state.archyves)}</td>
    

    【讨论】:

    • 这个库的最新版本提供了一种非常干净的 html 注入方式。 replace 方法是用您自己的 &lt;Image/&gt; 组件替换(例如)img 标记的好方法。
    【解决方案5】:

    对于那些仍在尝试的人,npm install react-html-parser

    当我安装它时,它每周有 123628 次下载。

    import ReactHtmlParser from 'react-html-parser'
    
    <div>{ReactHtmlParser(htmlString)}</div>
    

    【讨论】:

      【解决方案6】:

      如果你想在 React 中渲染原始 html,你可以使用以下代码

      <div dangerouslySetInnerHTML={{__html: `html-raw-goes-here`}} />
      

      示例 - 渲染

      测试是美好的一天

      【讨论】:

        【解决方案7】:

        这可以通过使用这个块{[]} 中的内容来解决,就像这样。为了更清楚起见,可以参考下面的示例。

        {[
           'abc',
           <b>my bold</b>, 
           'some other text'
        ]} 
        

        这将保留标签下文本的格式,而其他文本将被打印为纯文本。

        【讨论】:

          【解决方案8】:

          我发现了这个 js fiddle。像这样工作

          function unescapeHTML(html) {
              var escapeEl = document.createElement('textarea');
              escapeEl.innerHTML = html;
              return escapeEl.textContent;
          }
          
          <textarea className="form-control redactor"
                                    rows="5" cols="9"
                                    defaultValue={unescapeHTML(this.props.destination.description)}
                                    name='description'></textarea>
          

          jsfiddle链接

          【讨论】:

          • 不幸的是,文档在服务器渲染上不起作用。
          • 如果你这样做可能会import JSDOM from 'jsdom'; global.window = new JSDOM('', { url: 'http://localhost' }); global.document = global.window.document;idk goodluck
          • JSX 在哪里?
          【解决方案9】:

          您还可以使用 html-react-parser 中的 Parser()。 我也用过。 Link 共享。

          【讨论】:

            【解决方案10】:

            我开始使用名为 react-html-parser 的 npm 包

            【讨论】:

              【解决方案11】:

              现有答案中缺少的一个选项是使用&lt;React.Fragment&gt;在 React v16 及更高版本中可用)。我发现这是最好的,因为这允许您将任何 html 元素存储为 JSX 变量,并在以后引用它。也因为使用dangerouslySetInnerHTML 不安全。

              举例

              const App = () => {
                  const Windows = <React.Fragment>Microsoft <abbr title="Operating System">OS</abbr></React.Fragment>
              
                  return (
                    <ul>
                      <li>{Windows}</li>
                    </ul>
                  );
              };
              
              ReactDOM.render(<App />, document.getElementById("root"));
              <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
              <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
              <div id="root"></div>

              其他替代方案和注意事项:

              1. 如果您从外部来源获取 HTML,则不能使用此方法,因为获取的 HTML 将采用字符串格式。在这种情况下,您需要使用像 html-react-parser 这样的 HTML 解析器来解析 HTML
              2. 如果您没有任何键或属性,you can also use &lt;&gt;&lt;/&gt;&lt;React.Fragment&gt;&lt;/React.Fragment&gt; 的简写
              3. 请记住dangerouslySetInnerHTML is dangerous to use 因为可以通过脚本标签注入恶意客户端代码:
              4. @Brett 还建议other alternatives
              5. 注意: 在 JSX Variale 中使用引号
                • 你不应该用引号包围一个 JSX 变量(像一个常规变量) - 你应该用 &lt;React.Fragment&gt; &lt;/ React.Fragment&gt; 包围它
                • 您不应该在 JSX 变量的 html 标记中转义引号 - 例如,上面 &lt;abbr /&gt; 标记中的 title 包含未转义的引号。

              【讨论】:

              • const samplehtml = "

                Microsoft OS

                " const Windows = {samplehtml} React.Fragment> 这不起作用
              • 即使samplehtml 是一个JSX 变量,所以你也需要用&lt;React.Fragment&gt; 括起来——就像这样:const samplehtml = &lt;React.Fragment&gt;&lt;h1&gt;Microsoft &lt;abbr title="Operating System"&gt;OS&lt;/abbr&gt;&lt;/h1&gt;&lt;/React.Fragment&gt;
              • 我进行了建议的更改,但 html 仍然呈现为字符串
              • 您可能有语法错误。你不应该用引号包围一个 JSX 变量,你也不应该在你的&lt;abbr /&gt; 标签中转义引号。从上面的注释中复制samplehtml 变量。
              • samplehtml 是来自数据库的 html,所以它被引号包围我想将来自数据库的 htmlstring 转换为 jsx
              【解决方案12】:

              如果您事先知道要渲染的字符串中的标签;例如,如果在创建字符串时只允许某些标签;解决此问题的一种可能方法是使用 Trans 实用程序:

              import { Trans } from 'react-i18next'
              import React, { FunctionComponent } from "react";
              
              export type MyComponentProps = {
                  htmlString: string
              }
              
              export const MyComponent: FunctionComponent<MyComponentProps> = ({
                htmlString
              }) => {
                return (
                  <div>
                    <Trans
                      components={{
                        b: <b />,
                        p: <p />
                      }}
                    >
                      {htmlString}
                    </Trans>
                  </div>
                )
              }
              

              那么你可以像往常一样使用它

              <MyComponent
                  htmlString={'<p>Hello <b>World</b></p>'}
              />
              

              【讨论】:

                【解决方案13】:

                非常简单
                而且它完美运行

                import {settings} from '../settings';
                
                
                const NavBar = (props) => {
                    
                    let isLoggedIn=props.isLoggedIn;
                
                    let login_partial = "";
                    if(isLoggedIn)
                    {login_partial= <li>Log Out</li>;}
                    else{
                    login_partial=
                  <div>
                      <li>Login</li>
                    <li>Sign Up</li>
                </div>;
                   }
                
                    return(
                        <div>
                               <ul>
                                    <li>Home</li>
                                    <li>Products</li>
                                    {login_partial}
                                </ul>
                        </div>
                    )
                }
                export default NavBar;
                

                【讨论】:

                  猜你喜欢
                  • 2023-01-29
                  • 2021-01-19
                  • 1970-01-01
                  • 2016-12-24
                  • 1970-01-01
                  相关资源
                  最近更新 更多