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

React应用中如何从TypeScript调用嵌入HTML页面的JavaScript函数?

问题描述

基于Create React App开发React应用,现有一个基于webkit的HTML Viewer,该Viewer展示的HTML页面中嵌入了全局JavaScript函数sendMessage。需要在React的TypeScript按钮点击时,调用这个HTML页面中的sendMessage函数,此前尝试相关方案未成功。

相关代码片段

HTML页面中的全局sendMessage函数

function sendMessage(str) {
    theRenderArea.sendMessage(str);
}

注:theRenderArea是另一个JS脚本中定义的对象,此函数仅作为中转调用其内部的sendMessage方法。

HTML页面嵌入的theRenderArea.sendMessage实现

this.sendMessage = function(b) {
   if (this.isConnected()) {
      b = {
            type: "command",
            message: b.toString()
      };
      var a = new h;
      this.websocket.send(a.encode(b))
   }
};

TypeScript的Viewer组件

function Viewer() {
    return (
        <>
            <div id="loaderGroup" style={{display: "none"}}><div id="loader"></div><div id="loaderText">Network calibration</div></div>
            <div id="TheDiv"></div>
        </>
    )
}

export default Viewer

React中的按钮定义

<Button 
    style={{color: selected ? "#6A89FF": "#5B5C5D"}}
    onClick={sendMessage("some string")}>
    Interact
</Button>
解决步骤

1. 修正按钮的onClick绑定逻辑

原按钮代码中onClick={sendMessage("some string")}会在组件渲染时立即执行函数,而非点击时触发,需改为箭头函数包裹:

<Button 
    style={{color: selected ? "#6A89FF": "#5B5C5D"}}
    onClick={() => window.sendMessage("some string")}>
    Interact
</Button>

2. 解决TypeScript类型报错

由于TypeScript无法识别全局的sendMessage函数,需在项目中声明全局类型:

declare global {
  interface Window {
    sendMessage: (str: string) => void;
  }
}

// 可将这段代码放在项目根目录的`global.d.ts`文件中,或当前组件文件顶部

3. 确保HTML页面已加载完成

只有当HTML页面完全加载到Viewer中后,sendMessage函数才会存在于全局上下文,需根据Viewer的实现方式做对应处理:

  • iframe嵌入场景:给iframe添加加载完成监听,确认加载后再允许调用函数
    import { useRef, useEffect, useState } from 'react';
    
    function Viewer() {
      const iframeRef = useRef<HTMLIFrameElement>(null);
      const [isHtmlLoaded, setIsHtmlLoaded] = useState(false);
    
      useEffect(() => {
        if (iframeRef.current) {
          iframeRef.current.onload = () => setIsHtmlLoaded(true);
        }
      }, []);
    
      const handleSend = () => {
        if (isHtmlLoaded) window.sendMessage("some string");
      };
    
      return (
        <>
          <div id="loaderGroup" style={{display: "none"}}><div id="loader"></div><div id="loaderText">Network calibration</div></div>
          <div id="TheDiv">
            <iframe ref={iframeRef} src="你的HTML页面路径" />
          </div>
          <Button 
            style={{color: selected ? "#6A89FF": "#5B5C5D"}}
            onClick={handleSend}
            disabled={!isHtmlLoaded}>
            Interact
          </Button>
        </>
      )
    }
    
  • 独立webkit WebView场景(如Electron):需通过WebView的API执行脚本,而非直接访问window
    import { useRef } from 'react';
    
    function Viewer() {
      const webviewRef = useRef<Electron.WebviewTag>(null);
    
      const handleSend = () => {
        webviewRef.current?.executeJavaScript(`sendMessage("some string")`);
      };
    
      return (
        <>
          <div id="loaderGroup" style={{display: "none"}}><div id="loader"></div><div id="loaderText">Network calibration</div></div>
          <div id="TheDiv">
            <webview ref={webviewRef} src="你的HTML页面路径" />
          </div>
          <Button 
            style={{color: selected ? "#6A89FF": "#5B5C5D"}}
            onClick={handleSend}>
            Interact
          </Button>
        </>
      )
    }
    

4. 排查上下文隔离问题

如果上述方法仍不生效,需确认webkit Viewer是否开启了上下文隔离。若开启隔离,React的window和HTML页面的window属于不同上下文,无法直接访问,此时需要通过Viewer提供的通信API(如消息传递)来触发sendMessage函数。

内容的提问来源于stack exchange,提问作者cwietholt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 17:20:19