网页端和桌面端的electron通信Webview

1.electron使用Webview内镶嵌网页端

2.点击网页端触发electron的渲染进程

在网页端

javascript 复制代码
const sendDataToElectron = (data) => {
  console.log("🔥 [AiSystemEntrance] 准备发送数据到Electron:", data);

  // Electron webview 通信方法:使用特殊的 console 消息格式
  // 桌面端会监听 console-message 事件并解析这个特殊格式
  const message = `[ELECTRON_IPC]${JSON.stringify({
    type: "webview-message",
    data: data,
  })}[/ELECTRON_IPC]`;

  console.log(message); //使用console和桌面端通信

  // 也尝试其他方法作为备选--不过不生效,还是得是console通信
  try {
    // 尝试使用 postMessage (某些配置下可能工作)
    if (window.parent !== window) {
      window.parent.postMessage(
        {
          type: "webview-message",
          data: data,
        },
        "*"
      );
    }
  } catch (error) {
    console.error("❌ [AiSystemEntrance] postMessage 失败:", error);
  }

  console.log("📤 [AiSystemEntrance] 消息发送完成");
};

在electron端中的webview中使用handleWebViewReady

javascript 复制代码
 <webview
            key={tab.id}
            src={tab.url}
            className={`absolute inset-0 w-full h-[calc(100%-32px)] ${
              tab.active ? "visible" : "hidden"
            }`}
            webpreferences="nodeIntegration=true, contextIsolation=false"
            allowpopups="true"
            ref={(webview: WebViewElement | null) => {
              if (webview) {
                handleWebViewReady(webview);
              }
            }}
            onPageTitleUpdated={(e: WebViewTitleEvent) => {
              handleTitleUpdate(tab.id, e.title);
            }}
            onDidStartLoading={() => {
              console.log(`Started loading: ${tab.url}`);
            }}
            onDidFinishLoad={() => {
              console.log(`Finished loading: ${tab.url}`);
            }}
            onDidFailLoad={(e: WebViewLoadFailEvent) => handleLoadFail(e)}
          />

handleWebViewReady函数中使用原生 addEventListener 监听 console-message

javascript 复制代码
  const handleWebViewReady = useCallback(
    (webview: WebViewElement) => {
      webview.addEventListener("new-window", (e: NewWindowEvent) => {
        // console.log("New window requested:", e.url);
        addTab(e.url);
      });

      webview.addEventListener("will-navigate", (e: NavigationEvent) => {
        // console.log("Will navigate:", e.url);
      });

      webview.addEventListener("did-navigate", (e: NavigationEvent) => {
        // console.log("Did navigate:", e.url);
      });

      // 🔥 关键:使用原生 addEventListener 监听 console-message
      const handleConsoleMessage = (e: any) => {
        const message = e.message || "";
        
        // 检查是否是我们的特殊 IPC 消息格式
        if (
          message.includes("[ELECTRON_IPC]") &&
          message.includes("[/ELECTRON_IPC]")
        ) {
          try {
            // 提取 JSON 内容(处理 console.log 多参数格式:可能包含引号、空格等)
            const jsonStart =
              message.indexOf("[ELECTRON_IPC]") + "[ELECTRON_IPC]".length;
            const jsonEnd = message.indexOf("[/ELECTRON_IPC]");
            let jsonStr = message.substring(jsonStart, jsonEnd).trim();
            
            // 处理多种可能的格式:
            // 1. "[ELECTRON_IPC]" "{...}" "[/ELECTRON_IPC]"
            // 2. [ELECTRON_IPC] {...} [/ELECTRON_IPC]
            // 3. 移除首尾引号(单引号或双引号)
            jsonStr = jsonStr.replace(/^["']|["']$/g, "");
            // 移除可能的空格和换行
            jsonStr = jsonStr.trim();
            
            // console.log("🔍 [TabManager] 提取的 JSON 字符串:", jsonStr);
            
            const messageData = JSON.parse(jsonStr);

            // console.log("✅ [TabManager] 解析的 IPC 消息:", messageData);

            // 处理不同类型的消息
            if (messageData.type === "webview-message") {
              const data = messageData.data;

              // console.log("📦 [TabManager] 消息数据:", data);

              // 处理悬浮球点击事件
              if (data.type === "busEmitHandleFloatBallClick") {
          
                // 转发到主进程
                if (window.electron?.send) {
                // 渲染进程发送到主进程
                  window.electron.send("webview-open-legal-consultation", {
                    source: "webview",
                    action: "openLegalConsultation",
                    timestamp: Date.now(),
                  });
                } else {
                  console.error("❌ [TabManager] window.electron.send 不可用!");
                }
              } else {
                // 其他类型的消息也转发给主进程
                console.log("📤 [TabManager] 转发通用消息到主进程", data);
                window.electron?.send("webview-data", data);
              }
            }
          } catch (error) {
            console.error("❌ [TabManager] 解析 IPC 消息失败:", error);
            console.error("原始消息:", message);
          }
          return; // 已处理,直接返回
        }

        // 其他控制台消息正常输出
        console.log(`Webview console [${e.sourceId || 'unknown'}:${e.line || 'unknown'}]:`, message);
      };

      webview.addEventListener("console-message", handleConsoleMessage);
      console.log("✅ [TabManager] console-message 事件监听器已添加");
    },
    [addTab]
  );

重点,使用 React 的 onConsoleMessage 属性(可能不会触发)

javascript 复制代码
去掉代码:
onConsoleMessage={(e: WebViewConsoleEvent) =>
              handleConsoleMessage(e)
            }
使用原生 
webview.addEventListener("console-message", ...)
相关推荐
华仔啊17 分钟前
Vue 组件通信的 8 种最佳实践,你知道几种?
前端·vue.js
POLITE320 分钟前
Leetcode 234.回文链表 JavaScript (Day 9)
javascript·leetcode·链表
Ahtacca21 分钟前
Linux环境下前后端分离项目(Spring Boot + Vue)手动部署全流程指南
linux·运维·服务器·vue.js·spring boot·笔记
老前端的功夫1 小时前
TypeScript 全局类型声明:declare关键字的深度解析与实战
linux·前端·javascript·ubuntu·typescript·前端框架
EndingCoder2 小时前
TypeScript 入门:理解其本质与价值
前端·javascript·ubuntu·typescript·node.js
2501_946244782 小时前
Flutter & OpenHarmony OA系统弹窗对话框组件开发指南
javascript·flutter·microsoft
烟袅2 小时前
React 表单的控制欲:什么时候我们真得控制它了,什么时候该放养了?
前端·react.js
烟袅2 小时前
从定时器管理出发,彻底搞懂防抖与节流的实现逻辑
前端·javascript
计算机毕设VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue小区人脸识别门禁系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
前端小L2 小时前
贪心算法专题(十三):画地为牢的艺术——「划分字母区间」
javascript·算法·贪心算法