本文阅读须要花费一点时间,若是时间紧迫者能够阅读开头以及结尾总结。thanks
来咿呀快活呀html
首先咱们的选择能够在save在开发依赖上 npm install electron --save-dev 也能够全局安装electron npm install electron -g
这里有一段文档翻译有意思的话
Electron 可让你使用纯 JavaScript 调用丰富的原生(操做系统) APIs 来创造桌面应用。 你能够把它看做一个专一于桌面应用的 Node. js 的变体,而不是 Web 服务器。java
这不意味着 Electron 是绑定了 (GUI) 库的 JavaScript。 相反,Electron 使用 web 页面做为它的 GUI,因此你能把它看做成一个被 JavaScript 控制的,精简版的 Chromium 浏览器。awesomenode
主进程运行package.json 的main脚本被成为主进程。运行在主进程中的脚本将以建立 web 页面的方式显示一个 GUI。
(这让我想起了。之前作python 跟java时候gui主线程的感受。。。)python
Electron的web页面运行在一个成为渲染进程的进程中。 而且在页面与操做系统中得到一些低级别的交互git
主进程使用BrowserWindow实例建立页面github
每一个 BrowserWindow实例都在本身的渲染进程里运行页面。 web
当一个 BrowserWindow 实例被销毁后,相应的渲染进程也会被终止。chrome
渲染进程相互独立,主进程管理。npm
渲染进程只须要关心它们本身的页面。json
网页内是不能进行GUI操做的。
须要对应的渲染进程与主进程之间通讯。
一、使用HTML5 API 例如storage API、localstorage、sessionstorage或IndexedDB
二、IPC通讯( ipcRenderer 和 ipcMain)
三、RPC通讯(remote模块)
首先编码开始。
它管控文件与package.json相似。
主线程由main定义的入口文件建立
如下是不完整代码。大概的。
须要完整代码能够查看github地址。
项目目录大概为 todo -- addWindow.html -- main.js -- package.json -- window.html
入口文件是咱们的main.js,它是一个应用中的中心调度。
// 能够向使用nodejs时同样引入模块 // 这个也就是所谓的主进程,看起来就像是nodejs脚本 const electron = require('electron'); const url = require('url'); const path = require('path'); const {app,BrowserWindow,Menu,ipcMain} = electron; //设置环境 process.env.NODE_ENV = 'production'; let mainWindow; let addWindow; //listen for app to be ready app.on('ready',function(){ //1. 建立一个新的窗口 mainWindow = new BrowserWindow({}); //加载 html进窗口 mainWindow.loadURL(url.format({ pathname: path.join(__dirname,'window.html'), protocol: 'file:', //协议 slashes:true })); //file:/dirname/mainWindow.html //6. 大窗口关闭整个程序关闭 mainWindow.on('close',function(){ app.quit(); }) //2 .设置菜单 const mainMenu = Menu.buildFromTemplate(mainMenuTemplate); Menu.setApplicationMenu(mainMenu); }) //handle create add window function createAddWindow(){ //5. 新建窗口 addWindow = new BrowserWindow({ width: 300, height: 200, title: 'Add TODO list item' }); //load html into window addWindow.loadURL(url.format({ pathname: path.join(__dirname,'addWindow.html'), protocol: 'file:', //协议 slashes:true })); // 垃圾回收 addWindow.on('close',function(){ addWindow = null; }) } //7. 捕获子窗口ipc item:add // IPC通讯 ipcMain.on('item:add',function(e,item){ console.log('item'); mainWindow.webContents.send('item:add',item); addWindow.close(); }); const mainMenuTemplate = [{ label: 'File', submenu: [//3. 设置子菜单 { label: 'Add Item', click(){ //4. 新建窗口 createAddWindow(); } }, { label: 'Clear Items', click(){ mainWindow.webContents.send('item:clear'); } }, { label: 'Quit', accelerator: process.platform =='darwin'? 'Commond+Q':'Ctrl+Q',//快捷键作os版本区分 click(){ app.quit(); } } ] }]; // if mac , add empty object to menu if(process.platform =='darwin'){ mainMenuTemplate.unshift({}); } // 区分开发环境 if(process.env.NODE_ENV !== 'production'){ // add devtools mainMenuTemplate.push({ label:'Developer tools', submenu:[ { role:'reload' }, { label: 'Toggle DevTools', accelerator: process.platform =='darwin'? 'Commond+I':'Ctrl+I',//快捷键作os版本区分, click(item,focusedWindow){ //区分点击窗口 focusedWindow.toggleDevTools(); } } ] }); }
主进程设置好ipc通讯口。
监控渲染进程对应事件
<div class="container"> <form> <div> <label> Enter Item </label> <input type="text" id="item" autofocus> </div> <button class="btn waves-effect waves-light" type="submit">add Item</button> <!-- 将item发送到mainWindow --> </form> </div> const electron = require('electron'); const {ipcRenderer} = electron; const form = document.querySelector('form'); form.addEventListener('submit',function(e){ e.preventDefault(); // console.log(123); const item = document.querySelector('#item'); ipcRenderer.send('item:add',item.value); //使用ipc进行通讯 })
<nav> <div class="nav-wrapper"> <a class="brand-logo center"> TODO LIST </a> </div> </nav> <ul id="mainContainer"> </ul> <script> const electron = require('electron'); const {ipcRenderer} = electron; const ul = document.querySelector('#mainContainer'); ipcRenderer.on('item:add',function(e,item){ ul.className = 'collection'; const li = document.createElement('li'); li.className = 'collection-item'; const itemText = document.createTextNode(item); li.appendChild(itemText); // const li = '<li class="collection-item">'+item+'</li>'; ul.appendChild(li); // ul.innerHTML = ul.innerHTML+li; }) //clear items ipcRenderer.on('item:clear',function(e){ ul.innerHTML = ''; // if(ul.clildren.length == 0){ ul.className = ''; // } }) // Remove item by doubleclick ul.addEventListener('dblclick',function(e){ e.target.remove(); // console.log(ul.clildren.length); if(ul.children.length == 0){ ul.className = ''; } }) </script>
渲染进行的调试能够经过webContent的openDevTool api打开,调试web页面
const { BrowserWindow } = require('electron') let win = new BrowserWindow() win.webContents.openDevTools()
--inspect=[port] 监听 V8 引擎中有关 port 的调试器协议信息 --inspect-brk=[port] 和--inspector 同样,可是会在JavaScript 脚本的第一行暂停运行。
(感受这里有点想传统的debug nodejs in browser)
由于是使用chromium结合,因此咱们同时也可使用HTML5新特性在咱们渲染进程里
例如离线通知,离线缓存等。
本文写成较早,有些不妥之处还望谅解(2017年)
若有疑惑欢迎讨论。