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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 20:14:53