使用reactjs渲染原始html

所以这是唯一的方式来渲染原始html与reactjs?

// http://facebook.github.io/react/docs/tutorial.html
// tutorial7.js
var converter = new Showdown.converter();
var Comment = React.createClass({
render: function() {
var rawMarkup = converter.makeHtml(this.props.children.toString());
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
<span dangerouslySetInnerHTML={{__html: rawMarkup}} />
</div>
);
}
});

我知道有一些很酷的方法可以用JSX标记东西,但我主要感兴趣的是能够呈现原始html(包括所有的类、内联样式等)。像这样复杂的事情:

<!-- http://getbootstrap.com/components/#dropdowns-example -->
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-expanded="true">
Dropdown
<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
<li role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#">Something else here</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#">Separated link</a></li>
</ul>
</div>

我不想在JSX中重写所有这些内容。

也许我想错了。请纠正我。

408878 次浏览

除非绝对必要,否则不应该使用dangerouslySetInnerHTML。根据文档,“这主要用于与DOM字符串操作库合作”。当你使用它时,你就放弃了React的DOM管理的好处。

在您的情况下,转换为有效的JSX语法非常简单;只需将class属性更改为className。或者,正如上面的评论中提到的,你可以使用ReactBootstrap库,它将Bootstrap元素封装到React组件中。

现在有更安全的方法来呈现HTML。我在之前的回答在这里中提到了这一点。你有4个选项,最后一个使用dangerouslySetInnerHTML

渲染HTML的方法

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

    <div>{'First · Second'}</div> < / p >

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

    <div>{'First \u00b7 Second'}</div>

    <div>{'First ' + String.fromCharCode(183) + ' Second'}</div> < / p >

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

    <div>{['First ', <span>&middot;</span>, ' Second']}</div> < / p >

  4. 最后的手段 -插入原始HTML使用dangerouslySetInnerHTML

    <div dangerouslySetInnerHTML=\{\{__html: 'First &middot; Second'}} /> < / p >

你可以利用html-to-react npm模块。

注意:我是这个模块的作者,几个小时前刚刚发布了它。请随时报告任何bug或可用性问题。

我曾在一些快速且不太规范的情况下使用过这个短语:

// react render method:


render() {
return (
<div>
{ this.props.textOrHtml.indexOf('</') !== -1
? (
<div dangerouslySetInnerHTML=\{\{__html: this.props.textOrHtml.replace(/(<? *script)/gi, 'illegalscript')}} >
</div>
)
: this.props.textOrHtml
}


</div>
)
}
export class ModalBody extends Component{
rawMarkup(){
var rawMarkup = this.props.content
return { __html: rawMarkup };
}
render(){
return(
<div className="modal-body">
<span dangerouslySetInnerHTML={this.rawMarkup()} />


</div>
)
}
}

我试过这个纯成分:

const RawHTML = ({children, className = ""}) =>
<div className={className}
dangerouslySetInnerHTML=\{\{ __html: children.replace(/\n/g, '<br />')}} />

特性

  • 接受classNameprop(更容易设置样式)
  • \n替换为<br />(你经常想这样做)
  • 在像这样使用组件时,将内容放置为孩子们:
  • <RawHTML>{myHTML}</RawHTML>

我已经把组件放在Github的Gist: RawHTML:渲染HTML的ReactJS纯组件

下面是之前发布的一个不那么武断的RawHTML函数版本。它让你:

  • 配置标签
  • 可选地将换行符替换为<br />
  • 传递额外的道具,RawHTML将传递给创建的元素
  • 提供一个空字符串(RawHTML></RawHTML>)

下面是这个组件:

const RawHTML = ({ children, tag = 'div', nl2br = true, ...rest }) =>
React.createElement(tag, {
dangerouslySetInnerHTML: {
__html: nl2br
? children && children.replace(/\n/g, '<br />')
: children,
},
...rest,
});
RawHTML.propTypes = {
children: PropTypes.string,
nl2br: PropTypes.bool,
tag: PropTypes.string,
};

用法:

<RawHTML>{'First &middot; Second'}</RawHTML>
<RawHTML tag="h2">{'First &middot; Second'}</RawHTML>
<RawHTML tag="h2" className="test">{'First &middot; Second'}</RawHTML>
<RawHTML>{'first line\nsecond line'}</RawHTML>
<RawHTML nl2br={false}>{'first line\nsecond line'}</RawHTML>
<RawHTML></RawHTML>

输出:

<div>First · Second</div>
<h2>First · Second</h2>
<h2 class="test">First · Second</h2>
<div>first line<br>second line</div>
<div>first line
second line</div>
<div></div>

它会打破:

<RawHTML><h1>First &middot; Second</h1></RawHTML>

我使用了这个库叫做分析器。它满足了我的需要。

import React, { Component } from 'react';
import Parser from 'html-react-parser';


class MyComponent extends Component {
render() {
<div>{Parser(this.state.message)}</div>
}
};

我需要在我的头脑中使用一个带有onLoad属性的链接,其中div是不允许的,所以这给我带来了巨大的痛苦。我目前的解决方法是关闭原来的脚本标记,做我需要做的,然后打开脚本标记(被原来关闭)。希望这可以帮助那些没有其他选择的人:

<script dangerouslySetInnerHTML=\{\{ __html: `</script>
<link rel="preload" href="https://fonts.googleapis.com/css?family=Open+Sans" as="style" onLoad="this.onload=null;this.rel='stylesheet'" crossOrigin="anonymous"/>
<script>`,}}/>

dangerouslySetInnerHTML是React在浏览器DOM中使用innerHTML的替代品。一般来说,从代码中设置HTML是有风险的,因为很容易在不经意间让用户暴露在跨站点脚本(XSS)攻击之下。

在通过dangerouslySetInnerHTML将原始HTML注入DOM之前,更好/更安全的做法是对其进行消毒(例如,使用DOMPurify)。

DOMPurify -仅dom,超快速,超宽容的HTML, MathML和SVG XSS消毒器。DOMPurify使用一个安全的默认,但是提供了很多可配置性和钩子。

例子:

import React from 'react'
import createDOMPurify from 'dompurify'
import { JSDOM } from 'jsdom'


const window = (new JSDOM('')).window
const DOMPurify = createDOMPurify(window)


const rawHTML = `
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-expanded="true">
Dropdown
<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
<li role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#">Something else here</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#">Separated link</a></li>
</ul>
</div>
`


const YourComponent = () => (
<div>
{ <div dangerouslySetInnerHTML=\{\{ __html: DOMPurify.sanitize(rawHTML) }} /> }
</div>
)


export default YourComponent

这里有一个解决方案,可以归结为两个步骤:

  1. 使用内置api将原始HTML字符串解析为HTML Element
  2. 递归地将Element对象(及其子对象)转换为ReactElement对象。

注:这是一个学习的好例子。但是考虑其他答案中描述的选项,比如html-to-react库。

本方案特点:


下面是.jsx代码:

// RawHtmlToReactExample.jsx
import React from "react";


/**
* Turn a raw string representing HTML code into an HTML 'Element' object.
*
* This uses the technique described by this StackOverflow answer: https://stackoverflow.com/a/35385518
* Note: this only supports HTML that describes a single top-level element. See the linked post for more options.
*
* @param {String} rawHtml A raw string representing HTML code
* @return {Element} an HTML element
*/
function htmlStringToElement(rawHtml) {
const template = document.createElement('template');
rawHtml = rawHtml.trim();
template.innerHTML = rawHtml;
return template.content.firstChild;
}


/**
* Turn an HTML element into a React element.
*
* This uses a recursive algorithm. For illustrative purposes it logs to the console.
*
* @param {Element} el
* @return {ReactElement} (or a string in the case of text nodes?)
*/
function elementToReact(el) {
const tagName = el.tagName?.toLowerCase(); // Note: 'React.createElement' prefers lowercase tag names for HTML elements.
const descriptor = tagName ?? el.nodeName;
const childNodes = Array.from(el.childNodes);
if (childNodes.length > 0) {
console.log(`This element ('${descriptor}') has child nodes. Let's transform them now.`);
const childReactElements = childNodes.map(childNode => elementToReact(childNode)).filter(el => {
// In the edge case that we found an unsupported node type, we'll just filter it out.
return el !== null
});
return React.createElement(tagName, null, ...childReactElements);
} else {
// This is a "bottom out" point. The recursion stops here. The element is either a text node, a comment node,
// and maybe some other types. I'm not totally sure. Reference the docs to understand the different node
// types: https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
console.log(`This element ('${descriptor}') has no child nodes.`);


// For simplicity, let's only support text nodes.
const nodeType = el.nodeType;
if (nodeType === Node.TEXT_NODE) {
return el.textContent;
} else {
console.warn(`Unsupported node type: ${nodeType}. Consider improving this function to support this type`);
return null;
}
}
}


export function RawHtmlToReactExample() {
const myRawHtml = `<p>This is <em>raw</em> HTML with some nested tags. Let's incorporate it into a React element.`;
const myElement = htmlStringToElement(myRawHtml);
const myReactElement = elementToReact(myElement);


return (<>
<h1>Incorporate Raw HTML into React</h1>


{/* Technique #1: Use React's 'dangerouslySetInnerHTML' attribute */}
<div dangerouslySetInnerHTML=\{\{__html: myRawHtml}}></div>


{/* Technique #2: Use a recursive algorithm to turn an HTML element into a React element */}
{myReactElement}
</>)
}

这对我来说很管用:

    render()
{
var buff = '';
for(var k=0; k<10; k++)
{
buff += "<span> " + k + " </span>";
}


return (
<div className='pagger'>
<div className='pleft'>
<div dangerouslySetInnerHTML=\{\{__html: buff }} />
</div>
<div className='pright'>
<div className='records'>10</div>
<div className='records'>50</div>
<div className='records records_selected'>100</div>
<div className='records'>1000</div>
</div>
</div>
)
}

使用类似DOMPurify的东西来净化原始html,然后使用dangerouslySetInnerHTML,这样更安全

npm i dompurify

的类型

npm i --save-dev @types/dompurify

import React from 'react'
import * as DOMPurify from 'dompurify';


let dirty = '<b>hello there</b>';
let clean = DOMPurify.sanitize(dirty);


function MyComponent() {
return <div dangerouslySetInnerHTML=\{\{ __html: clean) }} />;
}

如果你有问题使它在你的特定设置中工作,考虑看看惊人的isomorphic-dompurify项目,它解决了人们可能遇到的许多问题。

npm i isomorphic-dompurify

import React from 'react'
import DOMPurify from 'isomorphic-dompurify';


const dirty = '<p>hello</p>'
const clean = DOMPurify.sanitize(dirty);


function MyComponent() {
return <div dangerouslySetInnerHTML=\{\{ __html: clean) }} />;
}

< p >演示 https://cure53.de/purify < / p > < p > https://github.com/cure53/DOMPurify < / p >

https://github.com/kkomelin/isomorphic-dompurify