You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 14:30:05