Electron.js中main.js向renderer.js发送数据失败求助
问题:Electron中IPC消息无法从主进程发送到渲染进程?
我是Electron.js新手,正在实现用户按下Cmd+F搜索主窗口文本的功能。已成功打开搜索窗口、捕获用户输入并发送至main.js,但使用mainWindow.webContents.send('highlight-text', searchTerm)将搜索词发回renderer.js时,renderer无法接收。已确认发送时mainWindow存在,控制台无报错,附上代码如下,恳请帮助。
Main.js
const { app, BrowserWindow, globalShortcut, ipcMain } = require('electron'); const path = require('path'); let mainWindow; function createWindow() { // Create the main browser window mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, contextIsolation: false, enableRemoteModule: true, contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'"], // Add other directives as needed }, } // preload: path.join(__dirname, 'renderer.js') }, }); // Load index.html in the window // mainWindow.loadFile('./index.html'); // Load Google in the main window mainWindow.loadURL('https://www.google.com'); // Open the DevTools (remove this line in production) mainWindow.webContents.openDevTools(); // Emitted when the window is closed mainWindow.on('closed', () => { mainWindow = null; }); // Register 'Ctrl+F' or 'Cmd+F' as a global shortcut to open the find dialog globalShortcut.register('CmdOrCtrl+F', () => { const searchWindow = new BrowserWindow({ width: 400, height: 200, webPreferences: { nodeIntegration: true, contextIsolation: false, enableRemoteModule: true }, }); searchWindow.loadFile(path.join(__dirname, 'search.html')); searchWindow.webContents.openDevTools(); // Handle closing the search window searchWindow.on('closed', () => { searchWindow = null; }); // mainWindow.webContents.send('open-find'); // console.log('open-find sent') }); } // Create the main window when the app is ready app.whenReady().then(() => { createWindow(); console.log('when Ready Called') // Create a new window for search functionality ipcMain.on('open-find', () => { console.log('open-find listened'); }); }); // Quit the app when all windows are closed (except on macOS) app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); // Create a new window when the app is activated (on macOS) app.on('activate', () => { if (mainWindow === null) { createWindow(); } }); // Unregister all global shortcuts when the app is about to quit app.on('before-quit', () => { globalShortcut.unregisterAll(); }); // Handle IPC messages from the renderer process ipcMain.on('perform-search', (event, searchTerm) => { console.log(`Performing search for: ${searchTerm}`); if (mainWindow && mainWindow.webContents) { try { setTimeout(() => { mainWindow.webContents.send('highlight-text', searchTerm); }, 100); } catch (error) { console.log(error); } } else { console.log('Main window is not available...'); } });
Renderer.js
const { ipcRenderer } = require('electron'); function highlight() { const searchInput = document.getElementById('searchInput'); const searchTerm = searchInput.value; // console.log(searchTerm); // alert(`search text: ${searchTerm}`); ipcRenderer.send('perform-search', searchTerm); } ipcRenderer.on('highlight-text', (event, searchTerm) => { console.log(event); // Highlight text in the main window based on the search term console.log('highlight-text-searchTerm: ', searchTerm) highlightText(searchTerm); }); function highlightText(searchTerm) { // Your logic to highlight the text in the main window const regex = new RegExp(searchTerm, 'gi'); const body = document.body; // Traverse the DOM and apply the highlighting traverseAndHighlight(body, regex); } function traverseAndHighlight(node, regex) { console.log('traverseAndHighlight called') if (node.nodeType === Node.TEXT_NODE) { const matches = node.nodeValue.match(regex); if (matches) { const span = document.createElement('span'); span.style.backgroundColor = 'yellow'; const replacedText = node.nodeValue.replace(regex, match => `<span style="background-color: yellow;">${match}</span>`); span.innerHTML = replacedText; node.parentNode.replaceChild(span, node); } } else if (node.nodeType === Node.ELEMENT_NODE) { for (const childNode of node.childNodes) { traverseAndHighlight(childNode, regex); } } }
P.S. 控制台无任何错误。
解决方案
核心问题是:你的renderer.js根本没在主窗口的页面中运行。主窗口加载的是外部网站https://www.google.com,这个页面不会自动加载你本地的renderer.js,所以监听highlight-text事件的代码从未执行,自然收不到主进程发来的消息。
针对这个问题,有两种解决方向:
方向1:针对外部页面实现高亮
直接通过Electron的webContents.executeJavaScript()方法,把高亮逻辑注入到外部页面中执行,无需依赖本地renderer.js。修改main.js中的perform-search事件处理代码:
ipcMain.on('perform-search', (event, searchTerm) => { console.log(`Performing search for: ${searchTerm}`); if (mainWindow && mainWindow.webContents) { // 转义搜索词中的单引号,避免脚本注入错误 const escapedTerm = searchTerm.replace(/'/g, "\\'"); // 注入高亮脚本到主窗口页面 mainWindow.webContents.executeJavaScript(` // 先清除之前的高亮标记 document.querySelectorAll('span[style="background-color: yellow;"]').forEach(el => { el.replaceWith(...el.childNodes); }); function traverseAndHighlight(node, regex) { if (node.nodeType === Node.TEXT_NODE) { const matches = node.nodeValue.match(regex); if (matches) { const span = document.createElement('span'); span.style.backgroundColor = 'yellow'; const replacedText = node.nodeValue.replace(regex, match => \`<span style="background-color: yellow;">\${match}</span>\`); span.innerHTML = replacedText; node.parentNode.replaceChild(span, node); } } else if (node.nodeType === Node.ELEMENT_NODE) { for (const childNode of node.childNodes) { traverseAndHighlight(childNode, regex); } } } const regex = new RegExp('${escapedTerm}', 'gi'); traverseAndHighlight(document.body, regex); `); } else { console.log('Main window is not available...'); } });
方向2:使用本地页面实现搜索
如果你是想在自己的本地页面中实现搜索功能,把主窗口的加载逻辑改回本地HTML:
// 替换原有的mainWindow.loadURL('https://www.google.com') mainWindow.loadFile('./index.html');
并确保index.html中引入了renderer.js:
<script src="./renderer.js"></script>
另外需要确认搜索窗口的search.html中,正确绑定了highlight函数到搜索按钮或输入框事件(比如点击按钮或回车触发)。
内容的提问来源于stack exchange,提问作者Ahsan Hasan
相关产品推荐
相关产品推荐

