[英]Issue while sending message from preload.js to main.js using ipcRenderer and ipcmain
我是使用 electron 進行桌面應用程序開發的初學者,當我嘗試使用 main.js 中的 ipcRenderer 和 ipcMain 將消息從預加載腳本發送到 main.js 時,下面的詳細信息顯示在 VScode 終端中並且沒有任何反應(沒有發生事件)甚至沒有控制台。日志工程
{
preventDefault: [Function: preventDefault],
sender: EventEmitter {
isDestroyed: [Function: isDestroyed],
destroy: [Function: destroy],
getBackgroundThrottling: [Function: getBackgroundThrottling],
setBackgroundThrottling: [Function: setBackgroundThrottling],
getProcessId: [Function: getProcessId],
getOSProcessId: [Function: getOSProcessId],
equal: [Function: equal],
_loadURL: [Function: _loadURL],
reload: [Function: reload],
reloadIgnoringCache: [Function: reloadIgnoringCache],
downloadURL: [Function: downloadURL],
getURL: [Function: getURL],
getTitle: [Function: getTitle],
isLoading: [Function: isLoading],
isLoadingMainFrame: [Function: isLoadingMainFrame],
isWaitingForResponse: [Function: isWaitingForResponse],
stop: [Function: stop],
canGoBack: [Function: canGoBack],
goBack: [Function: goBack],
canGoForward: [Function: canGoForward],
goForward: [Function: goForward],
canGoToOffset: [Function: canGoToOffset],
goToOffset: [Function: goToOffset],
canGoToIndex: [Function: canGoToIndex],
goToIndex: [Function: goToIndex],
getActiveIndex: [Function: getActiveIndex],
clearHistory: [Function: clearHistory],
length: [Function: length],
isCrashed: [Function: isCrashed],
forcefullyCrashRenderer: [Function: forcefullyCrashRenderer],
setUserAgent: [Function: setUserAgent],
getUserAgent: [Function: getUserAgent],
savePage: [Function: savePage],
openDevTools: [Function: openDevTools],
closeDevTools: [Function: closeDevTools],
isDevToolsOpened: [Function: isDevToolsOpened],
isDevToolsFocused: [Function: isDevToolsFocused],
enableDeviceEmulation: [Function: enableDeviceEmulation],
disableDeviceEmulation: [Function: disableDeviceEmulation],
toggleDevTools: [Function: toggleDevTools],
inspectElement: [Function: inspectElement],
setIgnoreMenuShortcuts: [Function: setIgnoreMenuShortcuts],
setAudioMuted: [Function: setAudioMuted],
isAudioMuted: [Function: isAudioMuted],
isCurrentlyAudible: [Function: isCurrentlyAudible],
undo: [Function: undo],
redo: [Function: redo],
cut: [Function: cut],
copy: [Function: copy],
paste: [Function: paste],
pasteAndMatchStyle: [Function: pasteAndMatchStyle],
delete: [Function: delete],
selectAll: [Function: selectAll],
unselect: [Function: unselect],
replace: [Function: replace],
replaceMisspelling: [Function: replaceMisspelling],
findInPage: [Function: findInPage],
stopFindInPage: [Function: stopFindInPage],
focus: [Function: focus],
isFocused: [Function: isFocused],
sendInputEvent: [Function: sendInputEvent],
beginFrameSubscription: [Function: beginFrameSubscription],
endFrameSubscription: [Function: endFrameSubscription],
startDrag: [Function: startDrag],
attachToIframe: [Function: attachToIframe],
detachFromOuterFrame: [Function: detachFromOuterFrame],
isOffscreen: [Function: isOffscreen],
startPainting: [Function: startPainting],
stopPainting: [Function: stopPainting],
isPainting: [Function: isPainting],
setFrameRate: [Function: setFrameRate],
getFrameRate: [Function: getFrameRate],
invalidate: [Function: invalidate],
setZoomLevel: [Function: setZoomLevel],
getZoomLevel: [Function: getZoomLevel],
setZoomFactor: [Function: setZoomFactor],
getZoomFactor: [Function: getZoomFactor],
getType: [Function: getType],
_getPreloadPaths: [Function: _getPreloadPaths],
getLastWebPreferences: [Function: getLastWebPreferences],
getOwnerBrowserWindow: [Function: getOwnerBrowserWindow],
inspectServiceWorker: [Function: inspectServiceWorker],
inspectSharedWorker: [Function: inspectSharedWorker],
inspectSharedWorkerById: [Function: inspectSharedWorkerById],
getAllSharedWorkers: [Function: getAllSharedWorkers],
_print: [Function: _print],
_printToPDF: [Function: _printToPDF],
_setNextChildWebPreferences: [Function: _setNextChildWebPreferences],
addWorkSpace: [Function: addWorkSpace],
removeWorkSpace: [Function: removeWorkSpace],
showDefinitionForSelection: [Function: showDefinitionForSelection],
copyImageAt: [Function: copyImageAt],
capturePage: [Function: capturePage],
setEmbedder: [Function: setEmbedder],
setDevToolsWebContents: [Function: setDevToolsWebContents],
getNativeView: [Function: getNativeView],
incrementCapturerCount: [Function: incrementCapturerCount],
decrementCapturerCount: [Function: decrementCapturerCount],
isBeingCaptured: [Function: isBeingCaptured],
setWebRTCIPHandlingPolicy: [Function: setWebRTCIPHandlingPolicy],
getWebRTCIPHandlingPolicy: [Function: getWebRTCIPHandlingPolicy],
takeHeapSnapshot: [Function: takeHeapSnapshot],
setImageAnimationPolicy: [Function: setImageAnimationPolicy],
_getProcessMemoryInfo: [Function: _getProcessMemoryInfo],
id: 1,
session: [Getter],
hostWebContents: [Getter],
devToolsWebContents: [Getter],
debugger: [Getter],
mainFrame: [Getter],
_windowOpenHandler: null,
_events: [Object: null prototype] {
'-ipc-message': [Function (anonymous)],
'-ipc-invoke': [Function (anonymous)],
'-ipc-message-sync': [Function (anonymous)],
'-ipc-ports': [Function (anonymous)],
crashed: [Function (anonymous)],
'render-process-gone': [Function (anonymous)],
'devtools-reload-page': [Function (anonymous)],
'-new-window': [Function (anonymous)],
'-will-add-new-contents': [Function (anonymous)],
'-add-new-contents': [Function (anonymous)],
login: [Function (anonymous)],
'ready-to-show': [Function (anonymous)],
'select-bluetooth-device': [Function (anonymous)]
},
_eventsCount: 13
},
frameId: 1,
processId: 4,
reply: [Function (anonymous)]
}
在按鈕上單擊來自預加載的 function 將被調用,這將向主進程發送消息
渲染器.js
button.addEventListener('click', function() {
window.LoadProductWindow.load();
});
preload.js
const {
contextBridge,
electron,
ipcRenderer
} = require('electron')
contextBridge.exposeInMainWorld('LoadProductWindow', {
load: () => ipcRenderer.send('load_product_window')
})
main.js
ipcMain.on('load_product_window', () => {
console.log('received')
});
請解決我的問題,並且我想在按鈕單擊添加新項目時添加新的 window 我該怎么做?
謝謝
毫無疑問,許多使用 Electron 的進程間通信和preload.js
的示例都很復雜且難以理解。 一旦你對Context-Isolation有了深刻的理解,事情就會開始到位。
我最近發現的主要問題是,許多人使用他們的preload.js
腳本打破了關注點分離的設計原則。 雖然這不是一個硬性規定,但通過將所有邏輯從純通信邏輯中移出來簡化您的preload.js
腳本,可以得到非常簡單、可讀的代碼。
首先,讓我們定義一個簡單易讀的preload.js
腳本。
在此腳本中,您將找到一個ipc
object,其中包含 3 個sendReceive
( send
、 receive
和發送接收),您可以在其中定義白名單通道名稱。 當從主線程或渲染線程調用時,它們將毫無阻礙地通過。 任何和所有其他未在這 3 個 arrays 中定義的通道名稱都將被阻止。
在這里,我已將通道名稱productWindow:load
添加到send
(從渲染到主線程)數組。
preload.js
(主線程)
'use strict';
// Import the necessary Electron components.
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// White-listed channels.
const ipc = {
'render': {
// From render to main.
'send': [
'productWindow:load'
],
// From main to render.
'receive': [],
// From render to main and back again.
'sendReceive': []
}
};
// Exposed protected methods in the render process.
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods.
'ipcRender', {
// From render to main.
send: (channel, args) => {
let validChannels = ipc.render.send;
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, args);
}
},
// From main to render.
receive: (channel, listener) => {
let validChannels = ipc.render.receive;
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`.
ipcRenderer.on(channel, (event, ...args) => listener(...args));
}
},
// From render to main and back again.
invoke: (channel, args) => {
let validChannels = ipc.render.sendReceive;
if (validChannels.includes(channel)) {
return ipcRenderer.invoke(channel, args);
}
}
}
);
接下來,我們將快速定義您的index.html
文件,該文件將包含 Javascript 功能,可在按下按鈕時向主線程發送 IPC 消息。
index.html
(渲染線程)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Main Page</title>
</head>
<body>
<label for="button">Product Window: </label>
<input type="button" id="button" value="Load Now">
</body>
<script>
document.getElementById('button').addEventListener('click', () => {
window.ipcRender.send('productWindow:load');
})
</script>
</html>
product.html
(渲染線程)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Product Page</title>
</head>
<body>
<h1>It Works..!</h1>
</body>
</html>
最后,在您的main.js
腳本(作為應用程序的入口點)中,我們使用 Electron 的ipcMain
模塊,特別是ipcMain.on()
方法通過productWindow:load
通道監聽消息。
main.js
(主線程)
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const electronIpcMain = require('electron').ipcMain;
const nodePath = require("path");
let mainWindow;
let productWindow;
function createMainWindow() {
const mainWindow = new electronBrowserWindow({
x: 0,
y: 0,
width: 800,
height: 600,
show: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: nodePath.join(__dirname, 'preload.js')
}
});
mainWindow.loadFile('index.html')
.then(() => { mainWindow.show(); });
return mainWindow;
}
function createProductWindow(parentWindow) {
const productWindow = new electronBrowserWindow({
x: 0,
y: 0,
width: 800,
height: 600,
parent: parentWindow,
show: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: nodePath.join(__dirname, 'preload.js')
}
});
productWindow.loadFile('product.html')
.then(() => { productWindow.show(); });
return productWindow;
}
electronApp.on('ready', () => {
mainWindow = createMainWindow();
});
// Let's listen for the 'productWindow:load' signal.
electronIpcMain.on('productWindow:load', () => {
productWindow = createProductWindow(mainWindow);
});
electronApp.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
electronApp.quit();
}
});
electronApp.on('activate', () => {
if (electronBrowserWindow.getAllWindows().length === 0) {
createMainWindow();
}
});
隨着您的 Electron 應用程序開始增長,您將希望開始將main.js
文件拆分為更小的文件,以“分離您的關注點”。 IE:將您不同的 window 創建代碼段移動到它們自己的文件中,包括它們相關的 IPC 代碼。
這將改善您的代碼結構,簡化可讀性並建立可維護的代碼庫。
發給 IPC 的消息中的第一個參數是 EVENT object,要獲得 object,您需要這樣做
ipcMain.on('myMessage',(event, myObj) => {
console.log(myObj)
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.