繁体   English   中英

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

[英]Render HTML string as real HTML in a React component

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

这有效:

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

这不会:

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

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

在此处输入图像描述

有什么建议?

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 SetInnerHTML 之前对其进行解码,这就是它被称为“危险的”的原因:)

工作示例:

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

我使用'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 等效项。

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

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

取而代之的是:

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

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

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

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

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

该节点是一个 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 的危险的SetInnerHTML 方法

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

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

这是我尝试过的方法以及出现问题的方法。

这有效:

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

这不是:

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

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

在此处输入图片说明

有什么建议么?

如果字符串中有 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

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

更新

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

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

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

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

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

您还可以使用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

根据上面的@Hou Soune,

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

为我工作。

解析字符串: '<p>Hello</p>'到元素<p>Hello</p>

 // 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>")

如果您可以控制 {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}
);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM