ChatGPT解决这个技术问题 Extra ChatGPT

在 React 组件中将 HTML 字符串呈现为真实的 HTML

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

这有效:

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

这不会:

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

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

https://i.stack.imgur.com/cI25q.png

有什么建议么?


D
Dexter

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

但是,如果描述是 <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 应该只渲染它吗?
你能在这里粘贴 console.log(this.props.match.description);
一个例子:&lt;p&gt;&lt;strong&gt;Our Opportunity:&lt;/strong&gt;&lt;/p&gt;
在这种情况下,您需要使用 .innerHTML 或解码 HTMLEntities。
返回多行或带有标签的 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; } } 返回返回字符串; }
p
pixelearth

我使用'react-html-parser'

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

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

来源on npmjs.com

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

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


这个库在后台使用“dangerouslySetInnerHTML”吗?
来自其 github 描述:Converts HTML strings directly into React components avoiding the need to use dangerouslySetInnerHTML 来自 npmjs.com A 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.
对于 React 17.0+,我使用了一个名为“html-react-parser”的类似库,目前支持该库。 npmjs.com/package/html-react-parser
来自 html-react-parser 的 FAQ 部分:“这个库不是 XSS(跨站点脚本)安全的。” npmjs.com/package/html-react-parser
您可能需要安装: npm install react-html-parser
m
machineghost

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

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

而不是这个:

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

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

https://i.stack.imgur.com/LF1X0.png

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

https://i.stack.imgur.com/tAKRd.png

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


这就是问题所在。描述字符串是转义的 HTML。我取消了它,现在它工作正常。
请避免使用 dangerouslySetInnerHTML 而使用 react v16 中的 Fragment。检查@brad-adams 的 next answer
感谢@KunalParekh 的提及,但它们是不同的东西。我的回答只有在 html 位于您的应用程序中时才有效(这意味着它实际上是 JSX)。要将 HTML 从外部源解析为 jsx,您需要寻求另一种解决方案。
D
DᴀʀᴛʜVᴀᴅᴇʀ

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

安装

新PM:

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>

B
Brad Adams

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

您的示例中没有包含 html 的字符串。它是 jsx 或纯字符串。
好吧,从技术上讲,你是正确的@mrkvon,但是正如我所提到的,这个 solution 只有在你可以控制的情况下才有效。例如,不适用于渲染通过 API 提供的一些 raw html。在 Fragment API 之前,这对我来说一直很痛苦,因为它需要额外的 span 包装,这有时会与 flex 布局混淆。当我偶然发现这个问题寻找可能的解决方案时,我想我会分享 如何解决问题。
谢谢!这是在我的情况下唯一有效的解决方案。此外,回复 mrkvon 对此答案的评论:此答案确实包含 html,即 Some text <strong>wrapped with strong</strong> 包含 html 标签 strong
@BinitaBharati 但这不是一个字符串。如果你从 API 中得到一个字符串,比如“

This is a String

”(或者只是将一个字符串存储在一个变量中),当你把这个字符串放在 中时,输出仍然会包含 < p> 标签。
@布拉德亚当斯。不错的把戏。我可以看到它变得方便的实例。
L
Lorenzo Delana

我将 innerHTML 与一个 ref 一起使用来跨越:

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>
}

我喜欢这样,当你没有那么奢侈时,不需要额外的库或依赖服务器端。受到您的启发,但在我所做的类组件中 componentDidMount() { this.message.current.innerHTML = this.state.selectedMessage.body; } body 是我的转义 html。
对答案的一点解释可能会产生奇迹。
@letsbondiway 请参阅我的回答中的更新部分。
@LorenzoDelana 感谢您提供详细的更新答案。现在真的很有帮助。但是,我有一个问题 - 您认为此解决方案是否存在任何类型的安全风险?我的意思是像 XSS、HTML 注入等攻击。我的理解是这些是安全的,因为我们没有使用危险的SetInnerHTML
@letsbondiway 以直接方式设置或不设置 html 元素属性,如果不应用安全标准,innerHTML 可能会很危险;从我的角度来看,但当然我可能会遗漏一些东西,如果您知道自己在做什么以及如何从攻击者那里负面使用这些内容,则没有具体问题。作为反例,您可以定期使用框架提供的标准输入框,这当然很好,因为已经考虑了最佳实践,但是如果您将该文本用作原始 sql 查询的一部分,攻击者可能会注入重言式以提取所有数据。
H
Hou Soune

您只需使用 React 的危险SetInnerHTML 方法

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

或者您可以通过这种简单的方式实现更多功能:Render the HTML raw in React app


S
Salman Lone

就我而言,我使用了 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>")

同时,我不建议再使用 react-render-html 了。由于 snyk,它的包健康评分非常低:snyk.io/advisor/npm-package/react-render-html Html-react-parser 要好得多:snyk.io/advisor/npm-package/html-react-parser
B
Binita Bharati

我无法让 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>);
}

Y
Yanov

我用 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>)

M
MajiD

您还可以使用 Jumper Package 中的 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


A
Abdul Basit

// 对于打字稿导入解析,{ HTMLReactParserOptions } from "html-react-parser";从“domhandler/lib/node”导入{元素}; export function contentHandler(postContent: string) { const options: HTMLReactParserOptions = { replace: (domNode: Element) => { if (domNode.attribs) { if (domNode.attribs.id === 'shortcode') { return

简码
; } } }, };返回解析(postContent,选项); } // 用法:contentHandler("Hello World!")


B
BBRay

如果您可以控制 {this.props.match.description} 并且您使用的是 JSX。我建议不要使用“dangerouslySetInnerHTML”。

// 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}
);