如何在 JSX 中渲染脚本标签而不手动创建它
Posted
技术标签:
【中文标题】如何在 JSX 中渲染脚本标签而不手动创建它【英文标题】:How to render script tag inside JSX without manually create it 【发布时间】:2020-07-25 15:03:45 【问题描述】:我有从后端获取的 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>
为了在两个段落之间呈现代码块?此外,如果标签内的属性较多,也很难处理。
【问题讨论】:
好吧,这是特意设置的not to be executed 是的,有什么解决方法吗? 参考:***.com/questions/6432984/… 【参考方案1】:不是答案,只是一些反馈仅供参考。我在浏览器中做了一个实验。好像脚本标签被渲染了。但是里面的代码没有执行,不知道为什么。
// @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>
【讨论】:
这是因为出于安全原因,通过 innerHTML 注入的脚本标签不会执行:developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML 参考:github.com/facebook/react/issues/8838【参考方案2】:可能会有所帮助:
来自 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;
也可能有一个库:
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
制造危险
现在,当您想使用 dangerouslySetInnerHTML 但还需要执行 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
【讨论】:
以上是关于如何在 JSX 中渲染脚本标签而不手动创建它的主要内容,如果未能解决你的问题,请参考以下文章