我们都知道React提供了一个 dangerouslySetInnerHTML
属性来让我们展示html文本成DOM节点,比如
<div dangerouslySetInnerHTML={{ __html: '<h1>Hello World</h1>'}} />
那么如果需要执行带 script
标签的 html 文本,可能结果不会如你所愿。
比如我们现在有一串 html 代码如下
<h1>Hello World</h1>
<script type="text/javascript" charset="utf-8" >
console.log("hello")
</script>
我们还是使用 dangerouslySetInnerHTML
来执行html代码,你会发现,script
标签的代码无法被顺利执行。最终的结果只展示 Hello World
的节点。
那么如何实现 script
标签内执行呢?
Range.createContextualFragment
Range.createContextualFragment()
方法通过以 range 的开头(选定节点的父级)作为上下文节点来调用 HTML 片段解析算法 或者 XML 片段解析算法来返回 DocumentFragment
。如果 range 属于一个其 HTMLness bit 被设置了的 Document
则会应用 HTML 片段解析算法。在 HTML 的情况下,如果上下文节点为 html,由于历史原因,将使用 body 作为上下文来调用片段解析算法。
看官方的解释有点懵逼,简单来说就是可以通过 createContextualFragment
来解析文本,生成可执行代码,返回一个 documentFragment 类型的节点,就可以插入到 DOM 里面执行。
那么接下来我们来通过 React 来实现上述的功能。
const HTML = `
<h1>Hello World</h1>
<script type="text/javascript" charset="utf-8" >
console.log("hello")
</script>
`;
我们使用 ref
获取渲染后的 dom 节点,然后通过 js 代码动态插入创建的 fragment 即可。
export default function App() {
const ref = useRef();
useEffect(() => {
const node = document.createRange().createContextualFragment(HTML);
ref.current.appendChild(node);
}, []);
return (
<div>
<h1>HTML String</h1>
<div>
<div ref={ref}></div>
</div>
</div>
);
}
运行代码后可以在控制台上顺利输出 hello
结果了。