如何渲染HTML字符串作为真正的HTML?

以下是我尝试过的方法,以及出错的地方。

如此:

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

这不是:

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

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

enter image description here

有什么建议吗?

507960 次浏览

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'));

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

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

而不是这样:

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

如果转义,您应该从服务器端转换它。

The node is text because is escaping

节点为文本,因为已转义

The node is a dom node because isn't escaping

该节点是dom节点,因为没有转义

如果你可以控制包含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>
}

我使用" 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 组件避免使用危险的setinnerhtml 一个将HTML字符串转换为React组件的实用程序。 避免使用dangerlysetinnerhtml并转换标准HTML

.元素,属性和内联样式

如果您可以控制{this.props.match.description},并且您正在使用JSX。我建议不要使用“dangerlysetinnerhtml”。

// In JSX, you can define a html object rather than a string to contain raw HTML
let description = <h1>Hi there!</h1>;


// Here is how you print
return (
{description}
);

你只是使用了React的dangerlysetinnerhtml方法

<div dangerouslySetInnerHTML=\{\{ __html: htmlString }} />

或者你可以用这个简单的方法实现更多:在React应用程序中渲染HTML原始

我不能让npm buildreact-html-parser一起工作。然而,在我的情况下,我能够成功地使用https://reactjs.org/docs/fragments.html。我需要显示一些html unicode字符,但它们不应该直接嵌入到JSX中。在JSX中,它必须从组件的状态中选择。组件代码片段如下:

constructor()
{
this.state = {
rankMap : {"5" : <Fragment>&#9733; &#9733; &#9733; &#9733; &#9733;</Fragment> ,
"4" : <Fragment>&#9733; &#9733; &#9733; &#9733; &#9734;</Fragment>,
"3" : <Fragment>&#9733; &#9733; &#9733; &#9734; &#9734;</Fragment> ,
"2" : <Fragment>&#9733; &#9733; &#9734; &#9734; &#9734;</Fragment>,
"1" : <Fragment>&#9733; &#9734; &#9734; &#9734; &#9734;</Fragment>}
};
}


render()
{
return (<div class="card-footer">
<small class="text-muted">{ this.state.rankMap["5"] }</small>
</div>);
}

在我的例子中,我使用了react-render-html

首先通过npm i --save react-render-html安装包

然后,

import renderHTML from 'react-render-html';


renderHTML("<a class='github' href='https://github.com'><b>GitHub</b></a>")

我使用https://www.npmjs.com/package/html-to-react

const HtmlToReactParser = require('html-to-react').Parser;
let htmlInput = html.template;
let htmlToReactParser = new HtmlToReactParser();
let reactElement = htmlToReactParser.parse(htmlInput);
return(<div>{reactElement}</div>)

我使用innerHTML一起引用span:

import React, { useRef, useEffect, useState } from 'react';


export default function Sample() {
const spanRef = useRef<HTMLSpanElement>(null);
const [someHTML,] = useState("some <b>bold</b>");


useEffect(() => {
if (spanRef.current) {
spanRef.current.innerHTML = someHTML;
}
}, [spanRef.current, someHTML]);


return <div>
my custom text follows<br />
<span ref={spanRef} />
</div>
}

更新:

我删除了一些html状态,并添加了注释,以使示例更符合概念。

/**
* example how to retrieve a reference to an html object
*/


import React, { useRef, useEffect } from 'react';


/**
* this component can be used into another for example <Sample/>
*/
export default function Sample() {
/**
* 1) spanRef is now a React.RefObject<HTMLSpanElement>
* initially created with null value
*/
const spanRef = useRef<HTMLSpanElement>(null);


/**
* 2) later, when spanRef changes because html span element with ref attribute,
* follow useEffect hook will triggered because of dependent [spanRef].
* in an if ( spanRef.current ) that states if spanRef assigned to valid html obj
* we do what we need : in this case through current.innerHTML
*/
useEffect(() => {
if (spanRef.current) {
spanRef.current.innerHTML = "some <b>bold</b>";
}
}, [spanRef]);


return <div>
my custom text follows<br />
{/* ref={spanRef] will update the React.RefObject `spanRef` when html obj ready */}
<span ref={spanRef} />
</div>
}

如果你在字符串中有HTML,我建议使用名为html-react-parser的包。

安装

NPM:

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>

你也可以使用跳线包中的parseReactHTMLComponent。看一下就知道,它很简单,不需要使用JSX语法。

https://codesandbox.io/s/jumper-module-react-simple-parser-3b8c9?file=/src/App.js

关于跳线的更多信息:

https://github.com/Grano22/jumper/blob/master/components.js

NPM包:

https://www.npmjs.com/package/jumper_react

  // For typescript


import parse, { HTMLReactParserOptions } from "html-react-parser";
import { Element } from "domhandler/lib/node";


export function contentHandler(postContent: string) {
const options: HTMLReactParserOptions = {
replace: (domNode: Element) => {
if (domNode.attribs) {
if (domNode.attribs.id === 'shortcode') {
return <div className="leadform">Shortcode</div>;
}
}
},
};


return parse(postContent, options);
}


// Usage: contentHandler("<span>Hello World!</span>")