React Typescript项目中注入外部HTML/JS渲染Plotly图表的方案问询
React + TypeScript 注入带JS的Plotly HTML内容解决方案
你遇到的JS不执行问题是React的内置安全机制导致的:dangerouslySetInnerHTML 出于XSS防护考虑,不会执行插入内容中包含的任何JS代码,因此只能渲染静态HTML元素,Plotly的绘图逻辑无法触发。
以下是不同场景下的可行方案,推荐优先级从高到低:
方案1:iframe托管(最推荐)
完全隔离主应用和注入内容的执行上下文,无全局变量污染风险,原生支持HTML内JS执行,适配任意返回的完整HTML内容。
import { useRef, useEffect } from 'react'; interface PlotlyIframeProps { htmlContent: string; height?: string; width?: string; } const PlotlyIframe = ({ htmlContent, height = '500px', width = '100%' }: PlotlyIframeProps) => { const iframeRef = useRef<HTMLIFrameElement>(null); useEffect(() => { if (!iframeRef.current) return; const iframeDoc = iframeRef.current.contentDocument || iframeRef.current.contentWindow?.document; if (!iframeDoc) return; // 把完整HTML写入iframe iframeDoc.open(); iframeDoc.write(htmlContent); iframeDoc.close(); }, [htmlContent]); return <iframe ref={iframeRef} height={height} width={width} frameBorder="0" title="Plotly图表" />; }; export default PlotlyIframe;
使用时直接把API拿到的完整HTML字符串传给组件的htmlContent参数即可。
方案2:手动解析执行JS(无iframe场景使用)
如果不能使用iframe,可手动拆分HTML中的DOM和JS分别处理,注意:仅在你完全信任API返回内容的场景下使用,避免XSS攻击风险。
import { useRef, useEffect } from 'react'; interface PlotlyRendererProps { rawHtml: string; } const PlotlyRenderer = ({ rawHtml }: PlotlyRendererProps) => { const containerRef = useRef<HTMLDivElement>(null); useEffect(() => { if (!containerRef.current || !rawHtml) return; const parser = new DOMParser(); const doc = parser.parseFromString(rawHtml, 'text/html'); // 提取所有脚本内容 const scripts = doc.querySelectorAll('script'); const scriptCodes: string[] = []; scripts.forEach(script => { if (script.textContent) { scriptCodes.push(script.textContent); } script.remove(); }); // 渲染DOM结构 containerRef.current.innerHTML = doc.body.innerHTML; // 手动执行脚本 scriptCodes.forEach(code => { eval(code); }); }, [rawHtml]); return <div ref={containerRef} />; }; export default PlotlyRenderer;
补充注意:如果返回的HTML依赖外部Plotly资源,需要提前在主应用全局引入Plotly.js,否则执行JS时会出现Plotly is not defined报错。
方案3:优化结构彻底规避注入风险(可配合后端调整时最优)
如果后端可以修改返回格式,优先让接口直接返回Plotly绘图的三个核心参数:data、layout、config,无需注入HTML,直接使用react-plotly.js渲染,性能更好,完全无安全风险。
内容的提问来源于stack exchange,提问作者k3nz0
相关产品推荐
相关产品推荐

