在 ElectronJS 中动态执行 JavaScript
ElectronJS是一个开源框架,用于使用能够在 Windows、macOS 和 Linux 操作系统上运行的 HTML、CSS 和 JavaScript 等 Web 技术构建跨平台原生桌面应用程序。它将 Chromium 引擎和NodeJS组合成一个单一的运行时。
在 Electron 中,每个BrowserWindow实例都可以被认为是应用程序中的一个单独的网页。 Electron 使用BrowserWindow对象和webContents属性创建和控制这些BrowserWindow实例。在传统的 Web 应用程序中,我们可以在浏览器的控制台中输入JavaScript代码,以便在网页上执行。为了通过脚本实现相同的功能,我们需要使用浏览器插件或扩展程序。在 Electron 中, webContents属性为我们提供了某些 Instance 方法,通过这些方法我们可以在运行时在BrowserWindow Instance 中动态注入 JavaScript 代码。本教程将演示如何使用webContents属性的那些 Instance 方法。
我们假设您熟悉上述链接中涵盖的先决条件。为了使 Electron 正常工作,需要在系统中预先安装node和npm 。
- 项目结构:
示例:按照使用 ElectronJS 构建桌面应用程序中给出的步骤设置基本的 Electron 应用程序。复制文章中提供的main.js文件和index.html文件的样板代码。此外,执行package.json文件中提到的必要更改以启动 Electron 应用程序。我们将继续使用相同的代码库构建我们的应用程序。
包.json:
{
"name": "electron-execute",
"version": "1.0.0",
"description": "Inject JS Code in Page ",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"keywords": [
"electron"
],
"author": "Radhesh Khanna",
"license": "ISC",
"dependencies": {
"electron": "^8.3.0"
}
}
根据项目结构创建assets文件夹。在assets文件夹中创建sample.txt文件以进行演示。
示例.txt:
输出:此时,我们的基本电子应用程序已设置完毕。启动应用程序后,我们应该看到以下输出:
在 Electron 中动态注入 JS: BrowserWindow实例和webContents属性是Main Process的一部分。要在渲染器进程中导入和使用 BrowserWindow,我们将使用 Electron远程模块。
index.html:在该文件中添加以下代码段。
HTML
Dynamically Inject JS
Javascript
const electron = require('electron')
// Importing BrowserWindow from Main Process using Electron remote
const BrowserWindow = electron.remote.BrowserWindow;
var inject = document.getElementById('inject');
let win = BrowserWindow.getFocusedWindow();
// let win = BrowserWindow.getAllWindows()[0];
inject.addEventListener('click', (event) => {
win.webContents.executeJavaScript('const path = require("path");'
+ 'const fs = require("fs");'
+ 'fs.readFile(path.join(__dirname, "../assets/sample.txt"), '
+ '{encoding: "utf-8"}, function(err, data) {'
+ 'if (!err) { console.log("received data: " + data); }'
+ 'else { console.log(err); } });', true)
.then(console.log('JavaScript Executed Successfully'));
});
var print = document.getElementById('print');
print.addEventListener('click', (event) => {
var webSource = {
code: 'var numbers = [1, 2, 3, 4, 5];'
+ 'function filters(num) { return num > 2; }'
+ 'console.log(numbers.filter(filters));',
url: '',
startLine: 1
}
win.webContents.executeJavaScriptInIsolatedWorld(1, [webSource], true)
.then(console.log('JavaScript Executed Successfully'));
});
Read sample.txt File和Print an Array按钮还没有任何相关的功能。要更改此设置,请在index.js文件中添加以下代码。
index.js:
Javascript
const electron = require('electron')
// Importing BrowserWindow from Main Process using Electron remote
const BrowserWindow = electron.remote.BrowserWindow;
var inject = document.getElementById('inject');
let win = BrowserWindow.getFocusedWindow();
// let win = BrowserWindow.getAllWindows()[0];
inject.addEventListener('click', (event) => {
win.webContents.executeJavaScript('const path = require("path");'
+ 'const fs = require("fs");'
+ 'fs.readFile(path.join(__dirname, "../assets/sample.txt"), '
+ '{encoding: "utf-8"}, function(err, data) {'
+ 'if (!err) { console.log("received data: " + data); }'
+ 'else { console.log(err); } });', true)
.then(console.log('JavaScript Executed Successfully'));
});
var print = document.getElementById('print');
print.addEventListener('click', (event) => {
var webSource = {
code: 'var numbers = [1, 2, 3, 4, 5];'
+ 'function filters(num) { return num > 2; }'
+ 'console.log(numbers.filter(filters));',
url: '',
startLine: 1
}
win.webContents.executeJavaScriptInIsolatedWorld(1, [webSource], true)
.then(console.log('JavaScript Executed Successfully'));
});
说明: webContents.executeJavaScript(code, userGesture)方法只是简单地执行网页中的代码,即BrowserWindow实例。此方法返回一个Promise并使用执行代码的结果来解决它,或者如果代码本身的结果是被拒绝的Promise ,则Promise被拒绝。这意味着Promise可以根据执行代码的结果返回任何数据类型,包括对象。如果执行的代码抛出错误,它将显示在控制台上。如果执行的代码没有返回Promise而是实现了回调,那么这个Promise将被解析为void ,如上面的代码所示。它接受以下参数。代码执行将暂停,直到网页完全加载。在我们的代码中,通过单击Read sample.txt File按钮调用此方法。
- code: String该值不能为空。该值表示要在BrowserWindow实例中执行的代码。在上面的代码中,我们已经使用fs.readFile()方法读取了sample.txt文件的内容。 fs.readFile()实现回调并返回文件的内容。
- userGesture: Boolean (可选)在BrowserWindow实例中,一些 HTML API 像requestFullScreen只能通过用户的手势调用。可以通过将userGesture属性设置为true来消除此限制。默认值为false 。
webContents.executeJavaScriptInIsolatedWorld(worldId, scripts, userGesture)也执行网页中的代码,但它是在独立上下文中执行的。此方法还返回一个Promise ,它的行为方式与webContents.executeJavaScript()方法中描述的相同。它接受以下参数。在我们的代码中,通过单击Print an Array按钮调用此方法。
- worldId: Integer此值表示要在其中运行 JavaScript 代码的虚拟隔离世界的 ID。默认 worldID 为0 。 Electron 的contextIsolation功能使用999作为 worldID。我们可以在这里提供任何整数值。在这个虚拟隔离世界中执行的 JavaScript 代码无法与BrowserWindow实例的代码交互,它被评估为完全独立的代码。使用这种方法,我们可以创建任意数量的虚拟隔离世界来运行不同的 JavaScript 代码段。
- 脚本:webSource[]该属性接受一个webSource对象数组。因此,此方法可以在同一个世界中执行多个不同的代码块。每个webSource对象都接受以下参数。
- code: String该值不能为空。该值表示要在BrowserWindow实例中执行的代码。在上面的代码中,我们使用了array.filter()函数从一个样本数组中创建一个满足任何大于 2 的数字的条件的新数组。
- startLine:整数(可选)默认值为1 。顾名思义,此值表示应评估代码字符串的整数。
- userGesture: Boolean (可选)在BrowserWindow实例中,一些 HTML API 像requestFullScreen只能通过用户的手势调用。可以通过将userGesture属性设置为true来消除此限制。默认值为false 。
注意: webContents.executeJavaScript()方法可以与BrowserWindow实例的代码进行交互,因此我们也可以在代码中使用NodeJS函数。例如,我们可以使用require函数来导入fs和path模块,它们将被代码识别。 webContents.executeJavaScriptInIsolatedWorld()方法不能与BrowserWindow实例的代码交互,因此我们不能使用 NodeJS 函数,因为它无法识别它们。在webContents.executeJavaScriptInIsolatedWorld()方法中,我们只能执行纯客户端 JavaScript 代码。如果使用 NodeJS 函数,它将在控制台中显示错误。
要在Renderer Process中获取当前BrowserWindow实例,我们可以使用BrowserWindow对象提供的一些静态方法。
- BrowserWindow.getAllWindows():此方法返回活动/打开的 BrowserWindow 实例的数组。在这个应用程序中,我们只有一个活动的 BrowserWindow实例,它可以直接从 Array 中引用,如代码所示。
- BrowserWindow.getFocusedWindow():此方法返回在应用程序中聚焦的BrowserWindow实例。如果没有找到当前 BrowserWindow 实例,则返回null 。在这个应用程序中,我们只有一个活动的 BrowserWindow实例,可以直接使用该方法引用它,如代码所示。
输出: