在 React 组件中将 HTML 字符串渲染为真正的 HTML

IT技术 javascript html reactjs jsx
2021-02-07 20:09:25

这是我尝试过的方法以及它是如何出错的。

这有效:

<div dangerouslySetInnerHTML={{ __html: "<h1>Hi there!</h1>" }} />

这不会:

<div dangerouslySetInnerHTML={{ __html: this.props.match.description }} />

description 属性只是一个普通的 HTML 内容字符串。但是,由于某种原因,它呈现为字符串,而不是 HTML。

在此处输入图片说明

有什么建议?

6个回答

this.props.match.description字符串还是对象?如果它是一个字符串,它应该被转换为 HTML 就好了。例子:

class App extends React.Component {

constructor() {
    super();
    this.state = {
      description: '<h1 style="color:red;">something</h1>'
    }
  }
  
  render() {
    return (
      <div dangerouslySetInnerHTML={{ __html: this.state.description }} />
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));

结果:http : //codepen.io/ilanus/pen/QKgoLA?editors=1011

但是,如果 description<h1 style="color:red;">something</h1>没有引号'',您将得到:

​Object {
$$typeof: [object Symbol] {},
  _owner: null,
  key: null,
  props: Object {
    children: "something",
    style: "color:red;"
  },
  ref: null,
  type: "h1"
}

如果它是一个字符串并且您没有看到任何 HTML 标记,那么我看到的唯一问题就是错误标记。

更新

如果您正在处理 HTML 实体,则需要在将它们发送到之前对其进行解码,dangerouslySetInnerHTML这就是它被称为“危险”的原因:)

工作示例:

class App extends React.Component {

  constructor() {
    super();
    this.state = {
      description: '&lt;p&gt;&lt;strong&gt;Our Opportunity:&lt;/strong&gt;&lt;/p&gt;'
    }
  }

   htmlDecode(input){
    var e = document.createElement('div');
    e.innerHTML = input;
    return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
  }

  render() {
    return (
      <div dangerouslySetInnerHTML={{ __html: this.htmlDecode(this.state.description) }} />
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
this.props.match.description是一个字符串,而不是一个对象。错误的标记是什么意思?你的意思是未闭合的标签?React 应该不渲染它吗?
2021-03-13 20:09:25
一个例子: &lt;p&gt;&lt;strong&gt;Our Opportunity:&lt;/strong&gt;&lt;/p&gt;
2021-03-15 20:09:25
你能把console.log(this.props.match.description)粘贴在这里吗?
2021-03-31 20:09:25
在这种情况下,您需要使用 .innerHTML 或解码 HTMLEntities。
2021-04-08 20:09:25
返回多行或带有标签的 HTML 代码: function htmlDecode(input){ var e = document.createElement('div'); e.innerHTML = 输入;var returnString = ''; for (index = 0; index < e.childNodes.length; index++) { // 只是一个字符串的情况 if(e.childNodes[index].nodeValue){ returnString += e.childNodes[index].nodeValue; } // HTML 案例 if(e.childNodes[index].outerHTML){ returnString += e.childNodes[index].outerHTML; 返回返回字符串;}
2021-04-08 20:09:25

我使用'react-html-parser'

yarn add react-html-parser
import ReactHtmlParser from 'react-html-parser'; 

<div> { ReactHtmlParser (html_string) } </div>

来源在 npmjs.com

提升@okram 的评论以获得更多可见性:

来自其 github 描述:将 HTML 字符串直接转换为 React 组件,无需使用来自 npmjs.com 的危险的SetInnerHTML 将 HTML 字符串转换为 React 组件的实用程序。避免使用危险的 SetInnerHTML 并将标准 HTML 元素、属性和内联样式转换为它们的 React 等效项。

对于 React 17.0+,我使用了一个名为“html-react-parser”的类似库,目前支持该库。npmjs.com/package/html-react-parser
2021-03-13 20:09:25
来自 html-react-parser 的 FAQ 部分:“这个库不是 XSS(跨站点脚本)安全的。” npmjs.com/package/html-react-parser
2021-03-21 20:09:25
这应该是问题的实际答案。不管怎么说,还是要谢谢你。
2021-03-22 20:09:25
这个库在后台使用“dangerouslySetInnerHTML”吗?
2021-03-24 20:09:25
来自其 github 描述:Converts HTML strings directly into React components avoiding the need to use dangerouslySetInnerHTML来自 npmjs.comA utility for converting HTML strings into React components. Avoids the use of dangerouslySetInnerHTML and converts standard HTML elements, attributes and inline styles into their React equivalents.
2021-04-09 20:09:25

检查您尝试附加到节点的文本是否没有像这样转义:

var prop = {
    match: {
        description: '&lt;h1&gt;Hi there!&lt;/h1&gt;'
    }
};

取而代之的是:

var prop = {
    match: {
        description: '<h1>Hi there!</h1>'
    }
};

如果被转义,你应该从你的服务器端转换它。

该节点是文本,因为已转义

该节点是文本,因为已转义

该节点是一个 dom 节点,因为它没有被转义

该节点是一个 dom 节点,因为它没有被转义

感谢提及@KunalParekh,但它们是不同的东西。我的回答仅当 html 位于您的应用程序中时才有效(意味着它实际上是 JSX)。要将来自外部源的 HTML 解析为 jsx,您需要寻求另一种解决方案。
2021-03-17 20:09:25
这就是问题所在。描述字符串是转义的 HTML。我对它进行了转义,现在它工作正常。
2021-03-20 20:09:25
请避免使用react v16 中的dangerouslySetInnerHTML而是使用Fragment检查@brad-adams下一个答案
2021-03-29 20:09:25

如果您可以控制包含 html 的字符串的来源(即在您的应用程序中的某个地方),您可以从新<Fragment>API 中受益,执行以下操作:

import React, {Fragment} from 'react'

const stringsSomeWithHtml = {
  testOne: (
    <Fragment>
      Some text <strong>wrapped with strong</strong>
    </Fragment>
  ),
  testTwo: `This is just a plain string, but it'll print fine too`,
}

...

render() {
  return <div>{stringsSomeWithHtml[prop.key]}</div>
}
@布拉德亚当斯。不错的把戏。我可以看到它变得方便的实例。
2021-03-13 20:09:25
@BinitaBharati 但这不是字符串。如果你从 API 中得到一个字符串,比如“<p>This is a String</p>”(或者简单地将一个字符串存储在一个变量中),当你把这个字符串放在 <Fragment> 中时,输出仍然会包含 < p> 标签。
2021-03-27 20:09:25
谢谢!这是在我的案例中唯一有效的解决方案。此外,回应 mrkvon 对此答案的评论:此答案确实包含 html 即Some text <strong>wrapped with strong</strong>包含 html tag strong
2021-03-31 20:09:25
您的示例中没有包含 html 的字符串。它是 jsx 或纯字符串。
2021-04-02 20:09:25
好吧,从技术上讲,您是正确的@mrkvon,但是正如我所提到的,此解决方案仅在您可以控制“html”/jsx 时才有效。例如,不用于渲染通过 API 提供的一些原始html。FragmentAPI 出现之前,这对我来说总是很痛苦,这需要额外的span包装,有时会与 flex 布局混淆。当我偶然发现这个问题以寻找可能的解决方案时,我想我会分享如何解决问题的。
2021-04-02 20:09:25

如果字符串中有 HTML,我建议使用名为html-react-parser.

安装它:npm install html-react-parser或者如果你使用纱线,yarn add html-react-parser

像这样使用它

import parse from 'html-react-parser'
const yourHtmlString = '<h1>Hello</h1>'
<div>
    {parse(yourHtmlString)}
</div>

参考:https : //www.npmjs.com/package/html-react-parser

这确实非常有效!
2021-03-16 20:09:25
这工作得很好,不会向原始 HTML 添加任何额外的 div
2021-04-03 20:09:25