Electron 实战桌面计算器应用
原文地址:http://blog.gdfengshuo.com/article/22/
前言
Electron 是一个搭建跨平台桌面应用的框架,仅仅使用 JavaScript、HTML 以及 CSS,即可快速而容易地搭建一个原生应用。这对于想要涉及其他领域的开发者来说是一个非常大的福利。
原文作者:林鑫,作者博客:http://blog.gdfengshuo.com/
## 项目介绍
仓库地址:[lin-xin/calculator](https://github.com/lin-xin/calculator)
我这里通过 Electron 实现了仿 iPhone 的计算器,通过菜单可以切换横屏和竖屏,横屏有更多的运算。而对于 JavaScript 进行浮点数计算来说,精度丢失是个很大问题,所以我这里使用了第三方库 math.js 来解决这个精度的问题。
尽可能的实现了跟 iPhone 一样的运算:
- 1 + 2 × 3 = 7
- 3 += 6 (再按 = 等于 9)
- 0.1 + 0.2 = 0.3 (浮点数精度处理)


不过我下面并不是要讲计算器,而是用到的 Electron 的知识点。
生命周期
在主进程中通过 app 模块控制整个应用的生命周期。
当 Electron 完成初始化时触发 ready 事件:
app.on('ready', () => {
// 创建窗口、加载页面等操作
})
当所有的窗口都被关闭时会触发 window-all-closed 事件:
app.on('window-all-closed', () => {
if(process.platform !== 'darwin'){
app.quit(); // 退出应用
}
})
在开发中发现,没有监听该事件,打包后的应用关闭后,进程还保留着,会占用系统的内存。
窗口
本来我们的 html 只显示在浏览器中,而 electron 提供了一个 BrowserWindow 模块用于创建和控制浏览器窗口,我们的页面就是显示在这样的窗口中。
创建窗口
通过关键字 new 实例化返回 win 对象,该对象有丰富的方法对窗口进行控制。
win = new BrowserWindow({
width: 390, // 窗口宽度
height: 670, // 窗口高度
fullscreen: false, // 不允许全屏
resizable: false // 不允许改变窗口size,不然布局就乱了啊
});
加载页面
窗口创建完是一片空白的,可以通过 win.loadURL() 来加载要显示的页面。
const path = require('path');
const url = require('url');
win.loadURL(url.format({ // 加载本地的文件
pathname: path.join(__dirname, 'index.html'),
protocol: 'file',
slashes: true
}))
也可以直接加载远程链接 win.loadURL('http://blog.gdfengshuo.com');
菜单
桌面应用菜单栏是最常见的功能。Electron 提供了 Menu 模块来创建原生的应用菜单和 context 菜单,
const template = [ // 创建菜单模板
{
label: '查看',
submenu: [
{label: '竖屏', type: 'radio', checked: true}, // type 属性让菜单为 radio 可选
{label: '横屏', type: 'radio', checked: false},
{label: '重载',role:'reload'},
{label: '退出',role:'quit'},
]
}
]
const menu = Menu.buildFromTemplate(template); // 通过模板返回菜单的数组
Menu.setApplicationMenu(menu); // 将该数组设置为菜单
在子菜单中,通过点击竖屏或横屏来进行一些操作,那就可以给 submenu 监听 click 事件。
const template = [
{
label: '查看',
submenu: [
{
label: '横屏'
click: () => { // 监听横屏的点击事件
win.setSize(670,460); // 设置窗口的宽高
}
}
]
}
]
主进程和渲染进程通信
虽然点击横屏的时候,可以设置窗口的宽高,但是要如何去触发页面里的方法,这里就需要主进程跟渲染进程之间进行通信。
主进程,可以理解为 main.js 用来写 electron api 的就是主进程,渲染进程就是渲染出来的页面。
ipcMain
在主进程中可以使用 ipcMain 模块,它控制着由渲染进程(web page)发送过来的异步或同步消息。
const {ipcMain} = require('electron')
ipcMain.on('send-message', (event, arg) => {
event.sender.send('reply-message', 'hello world')
})
ipcMain 监听 send-message 事件,当消息到达时可以调用 event.sender.send 来回复异步消息,向渲染进程发送 reply-message 事件,也可以带着参数发送过去。
ipcRenderer
在渲染进程可以调用 ipcRenderer 模块向主进程发送同步或异步消息,也可以收到主进程的相应。
const {ipcRenderer} = require('electron')
ipcRenderer.on('reply-message', (event, arg) => {
console.log(arg); // hello world
})
ipcRenderer.send('anything', 'hello everyone');
ipcRenderer 可以监听到来自主进程的 reply-message 事件并拿到参数进行操作,也可以使用 send() 方法向主进程发送消息。
webContents
webContents 是一个事件发出者,它负责渲染并控制网页,也是 BrowserWindow 对象的属性。在 ipcMain 中的 event.sender,返回发送消息的 webContents 对象,所以包含着 send() 方法用于发送消息。
const win = BrowserWindow.fromId(1); // fromId() 方法找到ID为1的窗口
win.webContents.on('todo', () => {
win.webContents.send('done', 'well done!')
})
remote
remote 模块提供了一种在渲染进程(网页)和主进程之间进行进程间通讯(IPC)的简便途径。在 Electron 中,有许多模块只存在主进程中,想要调用这些模块的方法需要通过 ipc 模块向主进程发送消息,让主进程调用这些方法。而使用 remote 模块,则可以在渲染进程中调用这些只存在于主进程对象的方法了。
const {remote} = require('electron')
const BrowserWindow = remote.BrowserWindow // 访问主进程中的BrowserWindow模块
let win = new BrowserWindow(); // 其他的跟主进程的操作都一样
remote 模块除了可以访问主进程的内置模块,自身还有一些方法。
remote.require(module) // 返回在主进程中执行 require(module) 所返回的对象
remote.getCurrentWindow() // 返回该网页所属的 BrowserWindow 对象
remote.getCurrentWebContents() // 返回该网页的 WebContents 对象
remote.getGlobal(name) // 返回在主进程中名为 name 的全局变量(即 global[name])
remote.process // 返回主进程中的 process 对象,等同于 remote.getGlobal('process') 但是有缓存
shell 模块
使用系统默认应用管理文件和 URL,而且在主进程和渲染进程中都可以用到该模块。在菜单中,我想点击子菜单打开一个网站,那么就可以用到 shell.openExternal() 方法,则会在默认浏览器中打开 URL
const {shell} = require('electron');
shell.openExternal('https://github.com/lin-xin/calculator');
打包应用
其实将程序打包成桌面应用才是比较麻烦的事。我这里尝试了 electron-packager 和 electron-builder。
electron-packager
electron-packager 可以将项目打包成各平台可直接运行的程序,而不是安装包。
先使用 npm 安装: npm install electron-packager -S
运行打包命令:
electron-packager ./ 计算器 --platform=win32 --overwrite --icon=./icon.ico
打包会把项目文件包括 node_modules 也一起打包进去,当然可以通过 --ignore=node_modules 来忽略文件,但是如果项目中有用到第三方库,忽略的话则找不到文件报错了。
正确的做法就是严格区分 dependencies 和 devDependencies,打包的时候只会把 dependencies 的库打包,而使用 cnpm 安装的会有一大堆 .0.xx@xxx 的文件,也会被打包,所以最好不要用 cnpm
electron-builder
electron-builder 是基于 electron-packager 打包出来的程序再做安装处理,将项目打包成安装文件。
安装:npm install electron-builder -S
打包:electron-builder --win
打包过程中,第一次下载 electron 可能会出现连接超时,可以使用 yarn 试试。还有 winCodeSign 和 nsis-resources 也可能会失败,可以参考 electron-builder/issues 解决。
总结
Electron 用起来还是相对容易的,可以创建个简单的桌面应用,只是打包的过程比较容易遇到问题,网上好像也有一键打包的工具,没尝试过。以上也都是基于 windows 7 的实践,毕竟没有 Mac 搞不了。
更多文章:linxin/blog
Electron 实战桌面计算器应用的更多相关文章
- C++程序设计语言(特别版) -- 一个桌面计算器
前言 这里要介绍各种语句和表达式,将通过一个桌面计算器的程序做些事情,该计算器提供四种座位浮点数的中缀运算符的标准算术运算. 这个计算器由四个部分组成:一个分析器,一个输入函数,一个符号表和一个驱动程 ...
- 使用 Electron 构建桌面应用(拖动控制篇)
使用 Electron 构建桌面应用(拖动控制篇) 当窗口被定义了大小,我们也就是在自定义这个窗口,使得它不可拉伸没有框架,让它看起来就像一个真正的声效器浮在桌面上. 现在问题来了 – 要如何移动或者 ...
- AngularJS 和 Electron 构建桌面应用
译]使用 AngularJS 和 Electron 构建桌面应用 原文: Creating Desktop Applications With AngularJS and GitHub Electro ...
- MVVM 实战之计算器
MVVM 实战之计算器 android DataBinding MVVM calculator Model View 布局文件 Fragment ViewModel 结束语 前些日子,一直在学习基于 ...
- [转] electron实战开发详细流程
[From] http://www.myk3.com/arc-8856.html 很久没有更新博客,人越来越懒了,唉 说好做的electron教程距离上次玩electron已经过去了好几个月了.. 这 ...
- 使用 AngularJS 和 Electron 构建桌面应用
GitHub 的 Electron 框架(以前叫做 Atom Shell)允许你使用 HTML, CSS 和 JavaScript 编写跨平台的桌面应用.它是io.js 运行时的衍生,专注于桌面应用而 ...
- electron --- 构建桌面应用
最近无意间看到了electron和nw的相关信息,感到很惊讶,因为学习前端也有一段时间了,竟然发现js还有这么强大的功能,因为js不仅可以写网页.写webapp.写hybrid,以及前不久出现的小程序 ...
- 使用Electron开发桌面应用
Electron 框架的前身是 Atom Shell,可以让你写使用 JavaScript,HTML 和 CSS 构建跨平台的桌面应用程序.它是基于io.js 和 Chromium 开源项目,并用于在 ...
- 用Electron开发桌面应用app的相关文献集锦
1. 超棒的发声器(项目实战) 原文点此链接 2. Electron中文文档 原文点此链接
随机推荐
- jquery-ajax实现文件上传异常处理web.multipart.MultipartException
异常如下: org.springframework.web.multipart.MultipartException: The current request is not a multipart r ...
- 关于Spring事务<tx:annotation-driven/>的理解(Controller可以使用@Transactional)
在使用SpringMvc的时候,配置文件中我们经常看到 annotation-driven 这样的注解,其含义就是支持注解,一般根据前缀 tx.mvc 等也能很直白的理解出来分别的作用.<tx: ...
- Codeforces 556 A Case of the Zeros and Ones
A. Case of the Zeros and Ones time limit per test 1 second memory limit per test 256 megabytes input ...
- python pygame--倒计时
import pygame,sys,time,datetime class decTime(object): #将秒转化为时分秒 def __init__(self,totalTime): self. ...
- 【机器学习笔记之一】深入浅出学习K-Means算法
摘要:在数据挖掘中,K-Means算法是一种 cluster analysis 的算法,其主要是来计算数据聚集的算法,主要通过不断地取离种子点最近均值的算法. 在数据挖掘中,K-Means算法是一种c ...
- ExecutorService的submit方法使用
在Java5之后,并发线程这块发生了根本的变化,最重要的莫过于新的启动.调度.管理线程的一大堆API了.在Java5以后,通过Executor来启动线程比用Thread的start()更好.在新特征中 ...
- NI笔试——大数加法
NI笔试: 1.找出字符串第一次出现的字符.用数组建立哈希表,然后再扫描字符串并判断次数是否为1. 2.大数加法,即字符串加法.因为之前写过乘法,就以为是乘法.然后就把乘法写上去了····= = 好了 ...
- ReactiveCocoa源码解读(一)
本着饮水思源的想法,面对ReactiveCocoa的强大功能,按捺不住心中的好奇心,于是走进其源码之中,一探ReactiveCocoa的魅力所在.虽然,耳闻其强大功能的核心是:信号,但一直不知道这个信 ...
- log4j配置文件,用时导入jar包buildPath且将配置文件改成log4j.properties即可
log4j.rootLogger=debug,CONSOLE,file#log4j.rootLogger=ERROR,ROLLING_FILElog4j.logger.cn.smbms=debuglo ...
- 最新eclipse国内镜像站,比ustc等站点资源新。
http://mirrors.neusoft.edu.cn/ 东软信息学院的镜像站,上面可以看到同步时间和状态很不错. 之前为了找最新的镜像站下载babel_language_packs r0.15. ...