Kết xuất html thô với Reacjs


154

Vì vậy, đây có phải là cách duy nhất để hiển thị html thô với Reacjs?

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

Tôi biết có một số cách hay để đánh dấu công cụ với JSX, nhưng tôi chủ yếu quan tâm đến việc có thể hiển thị html thô (với tất cả các lớp, kiểu nội tuyến, v.v.). Một cái gì đó phức tạp như thế này:

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

Tôi không muốn phải viết lại tất cả những điều đó trong JSX.

Có lẽ tôi đang nghĩ về điều này tất cả sai. Xin hãy sửa cho tôi.


1
Đó là gần như JSX. Nếu bạn kết xuất nhiều đánh dấu dưới dạng HTML thô, bạn sẽ mất lợi ích của việc sử dụng thư viện như React. Tôi khuyên bạn nên thực hiện các thay đổi nhỏ (như "class" -> "className") để React xử lý các phần tử.
Ross Allen

2
Đối với ví dụ cụ thể này, ai đó đã thực hiện công việc cho bạn , tuy nhiên câu hỏi vẫn là viết tắt của trường hợp chung.
Randy Morris

Câu trả lời:


43

Bạn có thể tận dụng html-to-reactmô-đun npm.

Lưu ý: Tôi là tác giả của mô-đun và vừa xuất bản nó vài giờ trước. Xin vui lòng báo cáo bất kỳ lỗi hoặc vấn đề sử dụng.


24
Nó có sử dụng một cách nguy hiểm SetInnerHTML trong nội bộ không?
Yash Sharma

2
Tôi chỉ kiểm tra mã. Nó dường như không sử dụng nguy hiểm SetInnerHTML.
Ajay Raghav

Mike bạn vẫn đang tích cực duy trì mô-đun npm này?
Daniel

Này Daniel, tôi không và một trong những người đóng góp đã tiếp quản nó và xuất bản bản phát hành cuối cùng 7 tháng trước. Xem github.com/aknuds1/html-to-react
Mike Nikles 11/07/19

Điều này không sử dụng bất kỳ nguy hiểm SetInnerHTML.
Tessaracter

185

Hiện tại có các phương pháp an toàn hơn để kết xuất HTML. Tôi đã đề cập đến điều này trong một câu trả lời trước đây . Bạn có 4 lựa chọn, lần sử dụng cuối cùng dangerouslySetInnerHTML.

Phương thức kết xuất HTML

  1. Dễ nhất - Sử dụng Unicode, lưu tệp dưới dạng UTF-8 và đặt thành charsetUTF-8.

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

  2. An toàn hơn - Sử dụng số Unicode cho thực thể bên trong chuỗi Javascript.

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

    hoặc là

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

  3. Hoặc một mảng hỗn hợp với các chuỗi và các phần tử JSX.

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

  4. Phương sách cuối cùng - Chèn HTML thô bằng cách sử dụng dangerouslySetInnerHTML.

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


Tất cả tôi cần là 3 hoặc 4
Nicolas S.Xu

tự hỏi những thuộc tính nào khác nhận được dangerouslySetInnerHTMLngoài __html
Juan Solano

30
Tôi thích những chủ đề này ... Ngẫu nhiên: "Làm bất cứ điều gì bạn có thể để không sử dụng # 4". Mọi người: "# 4 làm việc tuyệt vời!"
đào sâu

1
@JuanSolano không, theo các mục tự động hoàn thành trong môi trường TypeScript.
Andreas Linnert

Trong một câu hỏi tương tự, stackoverflow.com/questions/19266197/ , câu trả lời này đã không làm quá tốt. Có lẽ nó phù hợp hơn cho câu hỏi này hoặc có thể mọi người không đọc câu trả lời ...: D
425nesp

27

Tôi đã sử dụng điều này trong các tình huống nhanh chóng và bẩn thỉu:

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

7
Điều này không an toàn - nếu HTML chứa <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" onload="alert('test');">thì sao?
yjwong

11
Sẽ an toàn nếu bạn kiểm soát HTML được hiển thị
John

18

Tôi đã thử thành phần tinh khiết này:

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

Đặc trưng

  • Đưa classNameprop (dễ dàng hơn để tạo kiểu cho nó)
  • Thay thế \ncho <br />(bạn thường muốn làm điều đó)
  • Đặt nội dung như trẻ em khi sử dụng thành phần như:
  • <RawHTML>{myHTML}</RawHTML>

Tôi đã đặt thành phần này trong Gist tại Github: RawHTML: ReactJS thành phần thuần túy để kết xuất HTML


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

Công việc trên đối với tôi, tôi đã chuyển html sang cơ thể phương thức.
Jozcar 18/03/2017

11

nguy hiểm SetInnerHTML là sự thay thế của React để sử dụng InternalHTML trong DOM trình duyệt. Nói chung, việc thiết lập HTML từ mã rất rủi ro vì việc vô tình khiến người dùng của bạn gặp phải một cuộc tấn công kịch bản chéo trang (XSS).

Sẽ tốt hơn / an toàn hơn khi vệ sinh HTML thô của bạn (sử dụng ví dụ: DOMPurify) trước khi đưa nó vào DOM thông qua dangerouslySetInnerHTML.

DOMPurify - một công cụ khử trùng XSS chỉ dành cho DOM, siêu nhanh, dung nạp uber cho HTML, MathML và SVG. DOMPurify hoạt động với một mặc định an toàn, nhưng cung cấp rất nhiều cấu hình và hook.

Ví dụ :

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

Đây chính xác là những gì tôi đang tìm kiếm trong câu trả lời này. Nó sẽ có nhiều
upvote

6

Tôi đã sử dụng thư viện này được gọi là Parser . Nó làm việc cho những gì tôi cần.

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

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

3
21KB (8KB được nén). Tôi không thể biện minh cho mã trình duyệt.
Peter Bengtsson

thư viện này phá vỡ ứng dụng Expo của tôi
ekkis

5

dangerouslySetInnerHTMLkhông nên được sử dụng trừ khi thực sự cần thiết Theo các tài liệu, "Điều này chủ yếu để hợp tác với các thư viện thao tác chuỗi DOM" . Khi bạn sử dụng nó, bạn sẽ từ bỏ lợi ích của việc quản lý DOM của React.

Trong trường hợp của bạn, việc chuyển đổi thành cú pháp JSX hợp lệ là khá đơn giản; chỉ cần thay đổi classthuộc tính thành className. Hoặc, như đã đề cập trong các ý kiến ​​ở trên, bạn có thể sử dụng thư viện ReactBootstrap đóng gói các phần tử Bootstrap thành các thành phần React.


8
Cảm ơn câu trả lời của bạn. Tôi hiểu ý nghĩa bảo mật của việc sử dụng InternalHTML và tôi biết tôi có thể chuyển đổi nó thành JSX. Nhưng tôi đặc biệt hỏi về sự hỗ trợ của React trong việc sử dụng các đoạn mã HTML thô.
vinhboy

Chính xác ý bạn là gì bởi "Hỗ trợ của React cho việc sử dụng đoạn mã HTML thô"?
Breno Ferreira

2

Đây là một phiên bản ít quan tâm hơn của chức năng RawHTML được đăng trước đó. Nó cho phép bạn:

  • cấu hình thẻ
  • tùy chọn thay thế các dòng mới thành <br />của
  • vượt qua các đạo cụ bổ sung mà RawHTML sẽ chuyển đến phần tử đã tạo
  • cung cấp một chuỗi rỗng ( RawHTML></RawHTML>)

Đây là thành phần:

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

Sử dụng:

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

Đầu ra:

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

Nó sẽ phá vỡ:

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

0

Tôi cần sử dụng một liên kết với thuộc tính onLoad trong đầu, nơi div không được phép vì vậy điều này gây cho tôi nỗi đau đáng kể. Cách giải quyết hiện tại của tôi là đóng thẻ script gốc, làm những gì tôi cần làm, sau đó mở thẻ script (để được đóng bởi bản gốc). Hy vọng điều này có thể giúp một người hoàn toàn không có lựa chọn nào khác:

<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>`,}}/>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.