原文链接:
是由Github开发,用HTML,CSS和JavaScript来构建跨平台桌面应用程序的一个开源库。 Electron通过将 Chromium 和 Node.js合并到同一个运行时环境中,并将其打包为Mac,Windows和Linux系统下的应用来实现这一目的。
相信大部分前端同学都听说或者了解过 它是一个基于的JavaScript运行时, 而 是Google为发展自家浏览器Chrome而开启的开源浏览器项目,可以看成是是Chrome的先行版。大家较为熟悉的VS Code 和 Atom就是使用Electron来完成的。
从开发的角度来看, Electron application 本质上是一个 Node. js 应用程序。可以让前端开发者让你使用纯 JavaScript 调用丰富的原生操作系统APIs来创造桌面应用~
Quick Start
确认你的网络可以访问github , 若访问受限参考 来了解如何用代理、镜像和自定义缓存
你肯定已经已经安装好git和node了,那么只要:
# 官网已经有 electron-quick-start 仓库克隆下来git clone https://github.com/electron/electron-quick-start# 进入文件夹cd electron-quick-start# 安装依赖包并运行npm install && npm start复制代码
然后你的第一个桌面应用就开启了!
若你跟着一起实践到这里,肯定会发现界面有些许不同?我这里多了个调试界面,那么来看下代码看看。在Electron中main.js是入口文件:
//main.jsconst { app, BrowserWindow } = require('electron')// Keep a global reference of the window object, if you don't, the window will// be closed automatically when the JavaScript object is garbage collected.let winfunction createWindow () { // 创建浏览器窗口。 win = new BrowserWindow({ width: 800, height: 600 }) // 然后加载应用的 index.html。对应的index.html 就是初始界面。 win.loadFile('index.html') // 打开开发者工具 win.webContents.openDevTools() //关于win 窗口的生命周期我们之后再研究…… // 当 window 被关闭,这个事件会被触发。 win.on('closed', () => { // 取消引用 window 对象,如果你的应用支持多窗口的话, // 通常会把多个 window 对象存放在一个数组里面, // 与此同时,你应该删除相应的元素。 win = null })}//关于 app 主进程的生命周期我们之后再研究……// Electron 会在初始化后并准备// 创建浏览器窗口时,调用这个函数。// 部分 API 在 ready 事件触发后才能使用。app.on('ready', createWindow)// 当全部窗口关闭时退出。app.on('window-all-closed', () => { // 在 macOS 上,除非用户用 Cmd + Q 确定地退出, // 否则绝大部分应用及其菜单栏会保持激活。 if (process.platform !== 'darwin') { app.quit() }})app.on('activate', () => { // 在macOS上,当单击dock图标并且没有其他窗口打开时, // 通常在应用程序中重新创建一个窗口。 if (win === null) { createWindow() }})// 在这个文件中,你可以续写应用剩下主进程代码。// 也可以拆分成几个文件,然后用 require 导入。复制代码
与现有React工程结合
迫于不会Vue ,在这里介绍下React工程如何和Electron结合起来。
偷懒就直接使用 create-react-app 来创建react工程:
#若已安装 请忽略npm install -g create-react-appcreate-react-app react-electroncd react-electronnpm start复制代码
添加 Electron 配置并启动
一、 安装 Electron包
# 在 react-electron 目录下安装 Electron 包npm install -save electron复制代码
二、 添加main.js
在 react-electron 目录下添加main.js ,直接使用上面 main.js的内容 ,然后
//win.loadFile('index.html') 这一行替换为:win.loadFile('http://localhost:3000/')复制代码
这样就将入口界面指定到react的初始界面了。
三、 启动Electron!
修改 package.json ,添加 main homepage字段,并添加electron-start命令:
"main": "main.js", "homepage":".", "scripts": { "start": "react-scripts start", "build": "react-scriptsbuild", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject", "electron": "electron ." },}复制代码
启动 Electron:
# 启动react项目npm start# 启动electronnpm run electron复制代码
看到一篇 写create-react-app和Electron结合的不错,大家也可以参考这个。
四、在react中使用electron
直接在react中使用import electron会产生问题 ,可以写成这种形式:
const electron = window.require('electron');const fs = electron.remote.require('fs');const ipcRenderer = electron.ipcRenderer;复制代码
主进程和渲染进程
Electron 与web应用的区别不是很大,在原web应用的基础上添加主线程交互代码后,甚至可以将一个线上web应用迅速的包装成为一个客户端应用! Electron并且内集成了 Nodejs,Nodejs 在主进程和渲染进程中都可以使用,这为我们提供了npm成千上万的模块。
所以个人感觉应用Electron的重要在于理解主进程和渲染进程,和进程间的交互。其他API可以自己花点时间阅读文档。
运行Electron入口文件的进程(也就是上文运行main.js的进程)被称为主进程,它控制着整个 App 的生命周期,从打开到关闭。 它也管理着系统原生元素比如菜单,菜单栏,Dock 栏,托盘等。 主进程负责创建 APP 的每个渲染进程。而且整个 Node API 都集成在里面;
而在主进程创建的一个个web页面(对应上文中的win窗口)也都运行着自己的进程,即渲染进程,渲染进程各自独立,各自拥有自己的生命周期。与主进程不同的是,它能够同时存在多个而且运行在不一样的进程。而且它们也能够被隐藏。在通常的浏览器内,网页通常运行在一个沙盒的环境挡住并且不能够使用原生的资源。 然而 Electron 的用户在 Node.js 的 API 支持下可以在页面中和操作系统进行一些低级别的交互。
进程间通信
Electron提供了几种通信方式:
一 使用 和 :
ipc-renderer 和 ipc-main 异步交互:
//在渲染进程中:const {ipcRenderer} = require('electron')//发送asynchronous-message事件到主进程ipcRenderer.send('asynchronous-message', 'ping')//接收主进程的asynchronous-reply通知ipcRenderer.on('asynchronous-reply', (event, arg) => { console.log('asynchronous-reply : args:',arg) const message = `Asynchronous message reply: ${arg}` document.getElementById('async-reply').innerHTML = message})//在主进程中:const {ipcMain} = require('electron')//接收渲染进程的asynchronous-message通知ipcMain.on('asynchronous-message', (event, arg) => { //发送asynchronous-reply事件到渲染进程 event.sender.send('asynchronous-reply', { 'ping':'pong','num':'1'})})复制代码
ipc-renderer 和 ipc-main 同步交互:
//在渲染进程中:const {ipcRenderer} = require('electron')const syncMsgBtn = document.getElementById('sync-msg')syncMsgBtn.addEventListener('click', () => { const reply = ipcRenderer.sendSync('synchronous-message', 'ping') const message = `Synchronous message reply: ${reply}` document.getElementById('sync-reply').innerHTML = message})//在主进程中:const {ipcMain} = require('electron')ipcMain.on('synchronous-message', (event, arg) => { event.returnValue = 'pong'})复制代码
二 在渲染进程使用remote模块
// 在渲染进程打开提示对话框const {dialog} = require('electron').remotedialog.showMessageBox(options, (index) => { .... })复制代码
三 在主进程向渲染进程webContents发送消息
win.webContents.send('ping', 'whoooooooh!')复制代码
四 渲染进程之间的通信
在两个网页(渲染进程)间共享数据最简单的方法是使用浏览器中已经实现的 HTML5 API。 其中比较好的方案是用 Storage API, localStorage,sessionStorage 或者 IndexedDB。
你还可以用 Electron 内的 IPC 机制实现。将数据存在主进程的某个全局变量中,然后在多个渲染进程中使用 remote 模块来访问它。
// 在主进程中global.sharedObject = { someProperty: 'default value'}// 在第一个页面中require('electron').remote.getGlobal('sharedObject').someProperty = 'new value'// 在第二个页面中console.log(require('electron').remote.getGlobal('sharedObject').someProperty)复制代码