React中如何正确引入并渲染含document.write的第三方外部脚本
问题根因
你尝试注入的TryHackMe徽章脚本依赖document.write方法输出渲染内容,当页面初始DOM加载完成后,动态调用document.write会触发document.open清空现有DOM树,因此你原来的动态插入脚本的方案无法生效。
以下两种实现方案均可以保留脚本的动态更新能力,无需使用静态图片地址:
方案1:捕获
document.write输出(推荐) 临时覆写document.write方法捕获脚本输出内容,插入到指定容器后恢复原生方法,不会影响全局页面功能。
修改后的类组件代码如下:
import React, { Component } from "react"; export default class Awards extends Component { componentDidMount() { const targetContainer = document.getElementById('scriptTarget'); // 备份原生document.write const originalWrite = document.write; // 临时覆写write方法,把脚本输出内容插入目标容器 document.write = (content) => { targetContainer.innerHTML += content; }; const script = document.createElement("script"); script.src = "https://tryhackme.com/badge/170258"; script.async = true; // 脚本加载完成/失败后恢复原生write方法 script.onload = script.onerror = () => { document.write = originalWrite; }; targetContainer.appendChild(script); } render() { return ( <div> <div id="scriptTarget" /> <div className="main"> // 其他业务内容 </div> </div> ); } }
如果你使用函数组件,可以用以下实现:
import React, { useEffect, useRef } from "react"; const Awards = () => { const badgeRef = useRef(null); useEffect(() => { if (!badgeRef.current) return; const originalWrite = document.write; document.write = (content) => { badgeRef.current.innerHTML += content; }; const script = document.createElement("script"); script.src = "https://tryhackme.com/badge/170258"; script.async = true; script.onload = script.onerror = () => { document.write = originalWrite; }; badgeRef.current.appendChild(script); // 组件卸载时清理,避免内存泄漏 return () => { document.write = originalWrite; if (badgeRef.current) { badgeRef.current.innerHTML = ""; } }; }, []); return ( <div> <div ref={badgeRef} /> <div className="main"> // 其他业务内容 </div> </div> ); }; export default Awards;
方案2:iframe隔离加载
如果不想修改全局document.write方法,可以用空白iframe加载脚本,实现运行环境完全隔离,不会影响父页面任何逻辑:
import React, { useRef, useEffect } from 'react'; const Awards = () => { const iframeRef = useRef(null); useEffect(() => { const iframe = iframeRef.current; if (!iframe) return; const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; iframeDoc.open(); iframeDoc.write(` <html> <body style="margin:0;padding:0;border:none;overflow:hidden;"> <script src="https://tryhackme.com/badge/170258"></script> </body> </html> `); iframeDoc.close(); }, []); return ( <div> <iframe ref={iframeRef} width="200" height="70" frameBorder="0" scrolling="no" /> <div className="main"> // 其他业务内容 </div> </div> ); }; export default Awards;
你可以根据自己的项目技术栈和需求选择对应方案,两种方案都可以实现徽章的动态渲染更新。
内容的提问来源于stack exchange,提问作者Sidharth kaushik
相关产品推荐
相关产品推荐

