相关文章推荐
玩滑板的钥匙  ·  TypeError: ...·  1 周前    · 
沉稳的椅子  ·  苹果发布 Xcode 14.3.1 ...·  1 年前    · 
逃课的手套  ·  陈硕 - 知乎·  1 年前    · 
焦虑的书签  ·  document.referrer VS ...·  1 年前    · 

什么是 Electron?

使用 JavaScript, HTML 和 CSS 构建的跨平台桌面应用,能够兼容 Mac, Windows 和 Linux 环境,我们所熟悉的 Skype, Gihub Desktop, Visual Studio Code, Atom 等等软件,都是通过 Electron 进行构建的。

第一个 Electron 应用

官网提供了一个开箱即用的例子,在这里建议大家, node 的版本最好更新至当前发行版本或长期支持版本,避免在项目过程中产生未知问题。

# 克隆示例项目的仓库
git clone https://github.com/electron/electron-quick-start
# 进入这个仓库
cd electron-quick-start
# 安装依赖并允许
 npm install && npm start

没有繁琐的环境搭建和项目配置,只要你拥有基础的前端开发知识,就能够立刻上手 Electron,接下来我们再了解一下 Electron 的基础特性和使用方法

ELectron 进程

Electron 的底层是基于 Chromium 而设计的,故有且只有一个主进程 Main Process 和多个渲染进程 Renderer Process,主进程 Main Process 作为整个程序的入口点,可以使用和系统对接的 Electron API 创建菜单,上传文件等等,并创建渲染进程,每一个 Tab 就是一个独立的渲染进程,这样设计的好处在于,当一个 Tab 因为一些问题崩溃时,而不会影响到其他的进程

需要注意的是,主进程 Main Process 全面支持 Node.js,渲染进程全面支持 Node.js 和 DOM API,以及一部分的 Electron API

创建和控制浏览器窗口

// main.js
const { app, BrowserWindow } = require('electron')
app.on('ready', () => {
    const mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            nodeIntegration: true
    mainWindow.loadFile('index.html')

调用 Electron API 创建一个主进程窗口,网页功能参数 nodeIntegration 设为 true,即注入 Node 模块,可通过 mainWindow.load('https://github.com') 加载远程 URL 或 mainWindow.loadFile(urlLocation) 加载本地 HTML 文件

main.js 文件修改时,我们都需要关闭当前 electron .npm start 命令,并重新运行该命令才能看到修改后的效果,这对我们日常开发是非常不方便的,在这里建议大家下载 nodemon 来完成这部分工作,它可以监控文件的变化来完成相应的命令,这样就省去手动操作的过程

npm i nodemon -D

安装完毕之后,我们需要修改一下 start 的命令

"start": "nodemon --watch main.js --exec 'electron .'"

重新运行 npm start 命令即可生效

主进程中使用了 Node.js 的 require() 方法,接下来我们验证下渲染进程对 Node.js 和 DOM API 的支持

// renderer.js
alert(process.versions.electron)
window.addEventListener('DOMContentLoaded', () => {
  alert('say hi from the DOM side')

进程之间的通讯方式

当主进程完成更新,或我们在渲染进程上完成某些操作,例如点击按钮,需要调用到主进程上的特定 API 时,就需要进程之间进行通讯,Electron 使用 IPC (interprocess communication) 在进程之间进行通讯,这跟我们所熟悉的 DOM 的事件机制是一样的,都是通过事件驱动的方式进行

渲染进程通过 ipcRenderer.send() 方法进行消息传递,第一个参数为 string 的事件名称,第二个参数为事件内容,可为任意格式

// renderer.js
const { ipcRenderer } = require('electron')
window.addEventListener('DOMContentLoaded', () => {
  ipcRenderer.send('message', 'hi from renderer')

主进程通过 ipcMain.on() 方法进行接收,第一个参数同样为 string 的事件名称,需要跟传递方事件名一致,第二个参数为回调函数,该函数参数为事件对象 event 和事件内容 ...args

// main.js
const { app, BrowserWindow, ipcMain } = require('electron')
app.on('ready', () => {
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true
  mainWindow.loadFile('index.html')
  ipcMain.on('message', (event, arg) => {
    console.log(arg)

主进程在接收到渲染进程传递的信息后,可通过 event.sender.send() 方法进行消息传递,而渲染进程则通过 ipcRenderer.on() 方法进行接收

// main.js
ipcMain.on('message', (event, arg) => {
  console.log(arg)
  event.sender.send('reply', 'hi from main')
// renderer.js
ipcRenderer.on('reply', (event, arg) => {
  document.getElementById('msg').innerHTML = arg