Electron学习笔记(一)

相关笔记

笔记说明

文本为学习《Electron 实战 入门、进阶与性能优化 刘晓伦 著》时所记录的笔记 主要将书本上的案例运行一遍,针对原理部分并无相关记录。笔记记录于 2023年9月。

一、轻松入门

1、搭建开发环境

安装 yarn :

npm i -g yarn

创建一个文件夹,进行项目的初始化:

yarn init -y

配置 Electron 的镜像网站:

yarn config set electron_mirror https://registry.npmmirror.com/-/binary/electron/

使用 yarn 安装 Electron:

yarn add electron --dev

2、创建窗口界面

创建一个 index.html 文件,内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Electron</title>
</head>
<body>
    <h1>Hello World</h1>
</body>
</html>

新建一个 index.js 文件,内容如下:

const {app,BrowserWindow} = require('electron');

let win = null;

app.on('ready', function() {
    win = new BrowserWindow({
        // 为页面集成Node.js环境
        webPreferences: {
            nodeIntegration: true
        }
    });
    // 访问资源文件
    win.loadFile('index.html');

    // 程序启动后开启 开发者工具
    // win.webContents.openDevTools();
    
    win.on('close',function() {
        win = null;
    })
});

app.on('window-all-closed',function() {
    app.quit();
})

更新 package.json 文件:

"scripts": {
"start": "electron ./index.js"
},

启动项目:

yarn start

结果展示:

效果展示

3、调试主进程

点击调试按钮,创建 launch.json 文件 -> 选择Node.js环境

调试

修改 launch.json 文件如下:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "调试主进程",
            // type: 调试环境为 Node.js 环境
            "type": "node",
            "request": "launch",
            "cwd": "${workspaceRoot}",
            // runtimeExecutable: 指向的是批处理文件,该批处理文件用于启动 Electron
            // ${workspaceRoot} 是正在进行调试的程序的工作目录的绝对路径
            "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
            "windows": {
                "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"
            },
            // 此处的参数是主进程程序路径的简写形式,填写 "./index.js" 亦可
            "args": ["."],
            "outputCapture": "std"
        }
    ]
}

快捷键:

Ctrl+Shift+I:打开渲染进程的调试窗口

Ctrl+R:代码修改后,刷新界面

二、主进程和渲染进程

1、进程互访

注:原书籍中的代码由于 Electron 版本的更新,remote 模块无法直接导入使用,需要进行下载:

下载 remote 模块:

yarn add @electron/remote

更新 index.js 文件如下:(主进程代码

const {app,BrowserWindow} = require('electron');

app.on('ready', function() {
    win = new BrowserWindow({
        // 为页面集成Node.js环境
        webPreferences: {
            nodeIntegration: true,
            contextIsolation: false
        }
    });

    require("@electron/remote/main").initialize();
    require("@electron/remote/main").enable(win.webContents);

    // 访问资源文件
    win.loadFile('index.html');

    // 程序启动后开启 开发者工具
    // win.webContents.openDevTools();

    win.on('close',function() {
        win = null;
    })
});

app.on('window-all-closed',function() {
    app.quit();
})

参考链接:https://blog.csdn.net/m0_45961428/article/details/122982510

在 index.html 添加以下代码:

<button id="openDevToolsBtn">打开开发者工具</button>
<script>
    const remote =require('@electron/remote');
    document.querySelector('#openDevToolsBtn').addEventListener('click',function() {
        remote.getCurrentWindow().webContents.openDevTools();
    })
</script>

运行程序:

yarn start

运行结果:(点击按钮可打开开发者工具)

运行结果

2、渲染进程访问主进程类型

主进程代码:主进程代码

更新 index.html 文件如下:

<button id="makeNewWindow">创建新窗口</button>
<script>
    const remote = require('@electron/remote');

    // 在渲染进程中创建一个新的窗口
    document.querySelector('#makeNewWindow').addEventListener('click',function() {
        win = new remote.BrowserWindow({
            webPreferences: {
                nodeIntegration: true,
            }
        });
        win.loadFile('newWin.html');
    });
</script>

说明:创建 BrowserWindow 的过程依然在主进程中进行,是由 remote 模块通知主进程完成相应的操作的,主进程创建了 BrowserWindow 对象的实例后,把对象的实例以远程对象的形式返回给渲染进程。

3、渲染进程访问主进程自定义内容

主进程代码:主进程代码

新建文件 mainModel.js:

let {BrowserWindow} = require('electron');

exports.makeWin = function() {
    let win = new BrowserWindow({
        webPreferences: {
            nodeIntegration: true,
        }
    });
    return win;
}

更新 index.html 文件如下:

<button id="makeNewWindow2">创建新窗口2</button>
<script>
    const remote = require('@electron/remote');
    const mainModel = remote.require('./mainModel');

    let win2 = null;
    document.querySelector('#makeNewWindow2').addEventListener('click',function() {
        win2 = mainModel.makeWin();
        win2.loadFile('newWin.html');
    });
</script>

4、渲染进程向主进程发送消息

更新 index.html 文件:

<button id="sendMsg">向主进程发送消息</button>
<script>
    const {ipcRenderer} = require('electron');

    document.querySelector('#makeNewWindow2').addEventListener('click',() => {
        // msg:消息管道的名称
        ipcRenderer.send('msg',{name: 'xiaom'},{name: 'xiaoh'});
    });
</script>

index.js 文件添加以下内容:(其余主进程代码见:主进程代码

const {ipcMain} = require('electron');

ipcMain.on('msg',(event,param1,param2) => {
    console.log(param1);
    console.log(param2);
    console.log(event.sender);
})

运行结果:

运行结果

5、主进程向渲染进程发送消息

在主进程 index.js 文件中添加以下代码:

const {app,BrowserWindow} = require('electron');
const {ipcMain} = require('electron');

let win = null;

app.on('ready', function() {
    win = new BrowserWindow({
        // 为页面集成Node.js环境
        webPreferences: {
            nodeIntegration: true,
            contextIsolation: false
        }
    });

    // 监听渲染进程发来的消息,随后再次发回给渲染进程
    ipcMain.on('msg',(event,param1,param2) => {
        win.webContents.send('msg_main',param1,param2);
    })

    // 访问资源文件
    win.loadFile('index.html');

    win.on('close',function() {
        win = null;
    })
});

更新渲染进程 index.html 文件如下:

<button id="sendMsg">向主进程发送消息</button>
<script>
    const {ipcRenderer} = require('electron');

    // 接收 主进程发送的消息
    ipcRenderer.on('msg_main',(event,param1,param2) => {
        console.log(param1);
        console.log(param2);
        console.log(event.sender);
    })

    document.querySelector('#sendMsg').addEventListener('click',() => {
        ipcRenderer.send('msg',{name: 'xiaom'},{name: 'xiaoh'});
    });
</script>

运行程序后 -> 点击按钮(向主进程发送消息) -> Electron 程序控制台将会打印主进程发送来的消息。

运行结果:

运行结果

6、多个窗口的渲染进程接收主进程发送的消息

更新主进程 index.js 文件:

const {app,BrowserWindow} = require('electron');
const {ipcMain} = require('electron');

// 接收 渲染进程 发送来的消息 在VSCode控制台打印消息
ipcMain.on('msg',(event,param1,param2) => {
    console.log(param1);
    console.log(param2);
    console.log(event.sender);
});

let win = null;

app.on('ready', function() {
    win = new BrowserWindow({
        // 为页面集成Node.js环境
        webPreferences: {
            nodeIntegration: true,
            contextIsolation: false
        }
    });

    // 为了使 remote 模块能够使用需要执行以下操作
    require("@electron/remote/main").initialize();
    require("@electron/remote/main").enable(win.webContents);

    // 监听 渲染进程 发来的消息,随后再次发回给渲染进程
    ipcMain.on('msg',(event,param1,param2) => {
        // 单个窗口时使用:
        // win.webContents.send('msg_main',param1,param2);

        // 多个窗口时使用
        // 方法一:
        // event.sender.send('msg_main',param1,param2);
        // 方法二:
        event.reply('msg_main',param1,param2);
    })

    // 访问资源文件
    win.loadFile('index.html');

    win.on('close',function() {
        win = null;
    })
});

app.on('window-all-closed',function() {
    app.quit();
});

更新 index.html 文件如下:

<button id="makeNewWindow">创建新窗口</button>
<button id="sendMsg">向主进程发送消息</button>
<script>

    const remote = require('@electron/remote');
    const { ipcRenderer } = require('electron');

    // 在渲染进程中创建一个新的窗口
    document.querySelector('#makeNewWindow').addEventListener('click', function () {
        win = new remote.BrowserWindow({
            webPreferences: {
                nodeIntegration: true,
                contextIsolation: false
            }
        });
        win.loadFile('newWin.html');
    });

    // 监听主进程发送来的消息
    ipcRenderer.on('msg_main', (event, param1, param2) => {
        console.log(param1);
        console.log(param2);
        console.log(event.sender);
    })

    // 点击发送按钮 发送消息至主进程
    document.querySelector('#sendMsg').addEventListener('click', () => {
        ipcRenderer.send('msg', { name: 'xiaom' }, { name: 'xiaoh' });
    });
</script>

newWin.html 文件内容如下:

<h1>newWindow</h1>
<button id="sendMsg2">向主进程发送消息</button>
<script>
    const { ipcRenderer } = require('electron');

    // 监听主进程发送来的消息
    ipcRenderer.on('msg_main', (event, param1, param2) => {
        console.log(param1);
        console.log(param2);
        console.log(event.sender);
    })

    // 点击发送按钮 发送消息至主进程
    document.querySelector('#sendMsg2').addEventListener('click', () => {
        ipcRenderer.send('msg', { name: 'xiaod' }, { name: 'xiaoc' });
    });
</script>

7、渲染进程之间消息传递

一个程序有多个窗口,并要在窗口之间传递消息,可以通过主进程中转,此处通过win1先将消息发送给主进程,主进程再将消息发送给win2。

方法一:利用主进程进行中转

窗口(win1) --> 主进程(中转) --> 窗口(win2)

窗口(win2) --> 主进程(中转) --> 窗口(win1)

主进程 index.js 文件内容如下:

const {app,BrowserWindow} = require('electron');
const {ipcMain} = require('electron');

let win = null;

app.on('ready', function() {
    win = new BrowserWindow({
        // 为页面集成Node.js环境
        webPreferences: {
            nodeIntegration: true,
            contextIsolation: false
        }
    });

    require("@electron/remote/main").initialize();
    require("@electron/remote/main").enable(win.webContents);

    // 监听 窗口win1 (index.html) 发来的消息
    ipcMain.on('msg_1',(event,param1,param2) => {
        // 向 窗口win1 (index.html) 发送消息
        win.webContents.send('msg_main',param1,param2);
    });

    // 访问资源文件
    win.loadFile('index.html');

    // 程序启动后开启 开发者工具
    win.webContents.openDevTools();

    win.on('close',function() {
        win = null;
    })
});

app.on('window-all-closed',function() {
    app.quit();
})

窗口(win1) index.html 文件内容如下:

<h1>win1</h1>
<button id="makeNewWindow">创建新窗口win2</button>
<button id="sendMsg">向主进程发送消息</button>
<script>

    const remote = require('@electron/remote');
    const { ipcRenderer } = require('electron');

    // 在渲染进程中创建一个新的窗口(win2)
    document.querySelector('#makeNewWindow').addEventListener('click', function () {
        win2 = new remote.BrowserWindow({
            webPreferences: {
                nodeIntegration: true,
                contextIsolation: false
            }
        });
        win2.loadFile('win2.html');
        win2.webContents.openDevTools();

        // 接收 主进程 的消息后 向 win2 发送消息
        ipcRenderer.on('msg_main', (event, param1, param2) => {
            win2.webContents.send('msg_win2',param1,param2);
        });
    });

    // 接收 主进程 发送的消息
    ipcRenderer.on('msg_main', (event, param1, param2) => {
        console.log(param1);
        console.log(param2);
        console.log(event.sender);
    })

    // 点击按钮向 主进程 发送消息
    document.querySelector('#sendMsg').addEventListener('click', () => {
        ipcRenderer.send('msg_1', { name: 'xiaom' }, { name: 'xiaoh' });
    });
</script>

窗口(win2) win2.html 文件内容如下:

<h1>win2</h1>
<button id="sendMsg2">向主进程发送消息</button>
<script>
    const { ipcRenderer } = require('electron');

    // 接收 窗口 win1 (index.html) 发送来的消息
    ipcRenderer.on('msg_win2', (event, param1, param2) => {
        console.log(param1);
        console.log(param2);
        console.log(event.sender);
    })

    // 点击按钮向 主进程 发送消息
    document.querySelector('#sendMsg2').addEventListener('click', () => {
        ipcRenderer.send('msg_1', { name: 'xiaod' }, { name: 'xiaoc' });
    });
</script>

结果展示:

结果展示

方法二:单向传递

窗口(win1) --> 窗口(win2)

主进程 index.js 文件内容如下:(此方法无需主进程中转,所以主进程无需接收消息)

const {app,BrowserWindow} = require('electron');

let win = null;

app.on('ready', function() {
    win = new BrowserWindow({
        // 为页面集成Node.js环境
        webPreferences: {
            nodeIntegration: true,
            contextIsolation: false
        }
    });

    require("@electron/remote/main").initialize();
    require("@electron/remote/main").enable(win.webContents);

    // 访问资源文件
    win.loadFile('index.html');

    // 程序启动后开启 开发者工具
    win.webContents.openDevTools();

    win.on('close',function() {
        win = null;
    })
});

app.on('window-all-closed',function() {
    app.quit();
});

窗口(win1) index.html 文件内容如下:

<h1>win1</h1>
<button id="makeNewWindow">创建新窗口win2</button>
<button id="sendMsg">向窗口win2发送消息</button>
<script>

    const remote = require('@electron/remote');
    const { ipcRenderer } = require('electron');

    // 在渲染进程中创建一个新的窗口(win2)
    document.querySelector('#makeNewWindow').addEventListener('click', function () {
        win2 = new remote.BrowserWindow({
            webPreferences: {
                nodeIntegration: true,
                contextIsolation: false
            }
        });
        win2.loadFile('win2.html');
        win2.webContents.openDevTools();

        // 获取 窗口(win2) 的 webContents.id 并通过 ipcRenderer.sendTo 方法发送消息至 win2
        document.querySelector('#sendMsg').addEventListener('click', () => {
            ipcRenderer.sendTo(win2.webContents.id,'msg_win2', { name: 'xiaom' }, { name: 'xiaoh' });
        });
    });

</script>

窗口(win2) win2.html 文件内容如下:

<h1>win2</h1>
<script>
    const { ipcRenderer } = require('electron');

    // 接收 窗口(win1) 发送来的消息
    ipcRenderer.on('msg_win2', (event, param1, param2) => {
        console.log(param1);
        console.log(param2);
        console.log(event.sender);
    });
</script>

结果展示:

结果展示

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值