如何获取电子中的 DOM 元素?

我试图添加功能到按钮在 index.html文件如下: 我在 index.html中有一个按钮元素

<button id="auth-button">Authorize</button>

在应用程序的 main.js中,我有

require('crash-reporter').start();
console.log("oh yaeh!");
var mainWindow = null;


app.on('window-all-closed', function(){
if(process.platform != 'darwin'){
app.quit();
}
});


app.on('ready',function(){
mainWindow = new BrowserWindow({width:800, height : 600});
mainWindow.loadUrl('file://' + __dirname + '/index.html');


var authButton = document.getElementById("auth-button");
authButton.addEventListener("click",function(){alert("clicked!");});


mainWindow.openDevTools();


mainWindow.on('closed',function(){
mainWindow = null;
});
});

但是出现了如下错误: Uncaught Exception: ReferenceError: document is not defined

在构建电子应用程序时,可以访问 DOM 对象吗?或者有没有其他的方法可以给我所需要的功能?

92029 次浏览

DOM can not be accessed in the main process, only in the renderer that it belongs to.

There is an ipc module, available on main process as well as the renderer process that allows the communication between these two via sync/async messages.

You also can use the remote module to call main process API from the renderer, but there's nothing that would allow you to do it the other way around.

If you need to run something in the main process as a response to user action, use the ipc module to invoke the function, then you can return a result to the renderer, also using ipc.

Code updated to reflect actual (v0.37.8) API, as @Wolfgang suggested in comment, see edit history for deprecated API, if you are stuck with older version of Electron.

Example script in index.html:

var ipc = require('electron').ipcRenderer;
var authButton = document.getElementById('auth-button');
authButton.addEventListener('click', function(){
ipc.once('actionReply', function(event, response){
processResponse(response);
})
ipc.send('invokeAction', 'someData');
});

And in the main process:

var ipc = require('electron').ipcMain;


ipc.on('invokeAction', function(event, data){
var result = processData(data);
event.sender.send('actionReply', result);
});

You can use webContents.executeJavaScript(code[, userGesture, callback]) API to execute JavaScript code.

for example:

mainWindow.loadUrl('file://' + __dirname + '/index.html');
mainWindow.webContents.on('did-finish-load', ()=>{
let code = `var authButton = document.getElementById("auth-button");
authButton.addEventListener("click",function(){alert("clicked!");});`;
mainWindow.webContents.executeJavaScript(code);
});

As stated in this tutorial:

In Electron, we have several ways to communicate between the main process and renderer processes, such as ipcRenderer and ipcMain modules for sending messages, and the remote module for RPC style communication.

So you can follow the example in https://github.com/electron/electron-api-demos. You should have a js file for each html. In that js file, you can use require anytime you want.

Code in renderer.js:

const ipc = require('electron').ipcRenderer


const asyncMsgBtn = document.getElementById('async-msg')


asyncMsgBtn.addEventListener('click', function () {
ipc.send('asynchronous-message', 'ping')
})


ipc.on('asynchronous-reply', function (event, arg) {
const message = `Asynchronous message reply: ${arg}`
document.getElementById('async-reply').innerHTML = message
})

Code in ipc.html:

<script type="text/javascript">
require('./renderer-process/communication/sync-msg')
require('./renderer-process/communication/async-msg')
require('./renderer-process/communication/invisible-msg')
</script>

in my case the window was created by invoking window.open by default electron NodeIntegration is disabled, so you can't access the DOM of the other window. changing the property nativeWindowOpen to true fixed my issue.

// in main.ts
async function createWindow() {
const win = new BrowserWindow({
// ....
webPreferences: {
nativeWindowOpen: true,
}
})

Now i can access the window.document element when i create the window using window.open