如何在JSX内部呈现脚本标签而无需手动创建脚本标签

时间:2020-04-13 04:03:13

标签: javascript reactjs gatsby

我有从后端获取的HTML文档。这些文档包含2种标签,我想动态地渲染它们。这是我的源代码

const Content = ({ slug }) => {
  const [data, setData] = useState()
  useScript("https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js");

  useEffect(() => {

    api.posts.read({ slug: slug }, { formats: ["html", "plaintext"] }).then((resp) => {
      setData(resp)
    })
  }, [slug])

  if (data) {
    return (
      <>
        <SEO
          title={data.title}
          description={data.meta_description}
          canonical_url={data.canonical_url}/>
          <section className={'content'}>
            <h4 className={'content-title'}>{data.title}</h4>
            <div dangerouslySetInnerHTML={{ __html: data.html }}/>
          </section>
      </>
      )
  }
  return <Section>
    <CircularProgress style={{color: '#004D80'}}/>
    <p>Loading</p>
  </Section>
}

我尝试了这2种方法,但是它们都不适合我的用例。

1 <script>已呈现但未执行

<div dangerouslySetInnerHTML={{ __html: data.html }}/>

2

React: Script tag not working when inserted using dangerouslySetInnerHTML

这不适用于我的情况。如果我有类似的标签怎么办 <script src="https://gist.github.com/ogyalcin/66d0785998588ab50cf1908f8d43bb7b.js"></script>以便在两个段落之间呈现代码块?此外,如果标签内还有更多属性,则很难处理。

2 个答案:

答案 0 :(得分:0)

不是答案,只是一些反馈。我在浏览器中做了一个实验。好像脚本标记已呈现。但是里面的代码没有执行,不知道为什么。

// @jsx

function App() {
  return <div><h1>React</h1><div dangerouslySetInnerHTML={{ __html: window.thatScript }} /><h2>JS</h2></div>
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root'></div>
<script>
window.thatScript = '<script type="text/javascript">function foo() {console.log("yolo")} setTimeout(() => foo()};<\script>'
</script>

答案 1 :(得分:0)

可能有帮助:

来自create-react-app项目的示例代码。

import React, { useEffect } from 'react';
import './App.css';

function App() {
  const danger = '<script>alert("Hello world!")</script>';

  useEffect(() => {
    const el = document.querySelector('.danger');
    el.appendChild(document.createRange().createContextualFragment(danger));
  }, []);

  return (
    <div className='App'>
      <h1>Render and execute script tag</h1>
      <div className='danger'></div>
    </div>
  );
}

export default App;

Edit trusting-dream-i9ozk

可能还有一个图书馆:

dangerously-set-html-content

import React from 'react'
import InnerHTML from 'dangerously-set-html-content'

function Example {

  const html = `
    <div>This wil be rendered</div>
    <script>
      alert('testing')
    </script>
  `

  return (
    <InnerHTML html={html} />
  )
}

这同样适用于设置了src属性的脚本

分享好文章以获取更多信息: Render dangerous content with React

带来危险

现在,当您想危险地使用SetInnerHTML但又需要执行html内的任何脚本标签时会发生什么?这违反了HTML5规范,但是如果我们进一步研究innerHTML注入HTML的方式,我们会发现一些有趣的东西:

将指定的值解析为HTML或XML(基于文档类型),从而生成一个DocumentFragment对象,该对象代表新元素的新DOM节点集。

此DocumentFragment是文档的轻量级版本,它可以具有子节点,主要区别在于,由于是片段,因此实际上不是活动/主文档的一部分。

我们可以使用document.Range API创建一个DocumentFragment。

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

// InnerHTML component
function InnerHTML(props) {
  const { html } = props
  const divRef = useRef(null)

  useEffect(() => {
    const parsedHTML = document.createRange().createContextualFragment> (html)
    divRef.current.appendChild(parsedHTML)
  }, [])


  return (
    <div ref={divRef}></div>
  )
}

// Usage
function App() {
  const html = `
    <h1>Fragment</h1>
  `

  return (
    <InnerHTML html={html} />
  )
}

Reference on innerHTML

相关问题