electron初学习

Author Avatar
carvenzhang 7月 21, 2016
  • 在其它设备中阅读本文章

什么是electron

Electron 可以让你使用纯 JavaScript 调用丰富的原生 APIs 来创造桌面应用。
Electron 集合了 nodejs + Chromium 浏览器浏览器;这意味着前端开发者可以通过web的方式构建视图,通过nodejs去进行io操作,甚至可以在html文档中直接调用nodejs功能;
这可以使前端开发者以一种非常熟悉的方式去开发一款桌面应用。

当electron启动一个应用的时候,最创建一个主进程(就是启动的入口文件)。这个主进程负责与你系统的GUI交互,并为你的应用创建GUI(就是新建窗口);
借用Get社区的一个图片进行流程展示,一定要看哦;

继续向下看:

入手electron

一开始认识electron的时候,因为我一直在写react的缘故,我以为electron也会需要一大堆的辅助组件、复杂的构建流程,但是不是的,electron的使用出奇简单;
electron只需要一个核心组件electron-prebuilt就能运行,当然,你一定是已经安装了nodejs的;
习惯来说,我会全局安装一个electron-prebuilt

npm install -g electron-prebuilt

并在electron项目的文件夹中安装一个本地组件

npm install --save-dev electron-prebuilt

我们先驾起一个最简单的应用试一试:
新建 main.js

'use strict';
const { app, BrowserWindow } = require('electron');
let mainWindow;
app.on('ready', () => {
    mainWindow = new BrowserWindow({
        width: 600,
        height: 400
    });
    //引入视图文件
    mainWindow.loadURL("https://www.baidu.com");
});

在项目文件夹,运行

electron main.js

就可以看到一个桌面应用色生成,并加载了百度首页作为视图;

我是通过Get社区的用Electron开发桌面应用的教程来初步学习electron的,大家也可去过去膜拜,过程还是很详细的;
但是因为教程较老,很多语法已经不适用了。
比如

var app = require('app');
var BrowserWindow = require('browser-window');

应该改为

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

等等。
我在github上写了一个新版的,不过没有tag步骤,大家可以参考我的,使用教程里的一步步深入。
https://github.com/zjy01/electron-sound

当然,我自己也一步步搭建了一个小应用,大家也可以透过这个应用的搭建步骤去初步了解到electron。
我们会接触到:

Yeoman 生成器
在静态js资源中直接使用node模块
添加任务栏上的图标和菜单(Tray,Menu)
ipc通讯
右键菜单、粘贴板clipboard、弹窗dialog
按钮监听

electron – 二维码生成器

Yeoman

一般接触一个新的应用,我们还可以通过Yeoman去快速搭建一个项目结构。
关于Yeoman的介绍我在之前的博客里面写过:使用yeoman快速搭建前端项目结构
如果你还没有安装Yeoman,我们可以通过下面的命令安装

npm install -g yo

接着我们安装electron项目的生成器

npm install -g generator-electron

这样,我们就可以用yeoman去搭建一个electron项目了;

# 创建项目文件夹并进入(也可以右键创建)
mkdir electron-qr && cd electron-qr
# 生成文件结构
yo electron
# 耐心等待 npm install 完成

得到以下结构图

改一改目录结构,新建一个js,成以下模样

当然,要记得在html中引入index.js

<script src="index.js"></script>

并在主进程文件中修改视图文件地址

win.loadURL(`file://${__dirname}/app/index.html`);

可以打开看看啦

# 项目根目录执行
electron .

在静态js资源中直接使用node模块(添加生成二维码功能)


通过修改
index.htmlindex.css,使得视图如下所示

nodejs有一个模块qr-image可用于快速生成二维码,我们先安装

npm install --save qr-image

接着,我们编写app/index.js

const qr = require('qr-image'),//二维码模块
    qrInput = document.getElementById('msg'),//信息输入框
    qrBtn = document.getElementById('qr-btn'),//生成二维码按钮
    qrImg = document.getElementById('qr');//二维码图片区

let imgOfQr;
qrBtn.addEventListener('click', function () {
    let msg = qrInput.value;
    imgOfQr = qr.imageSync(msg, {//生成png
        'margin':1,
        'size':10,
        'ec_level':'Q'
    });

    qrImg.src = 'data:image/png;base64,'+imgOfQr.toString('base64')
});

如此,我们的主体功能就完成了,已经可以输入文字,生成二维码了,如此简单

下面我们来添加一下桌面应用特有的功能

添加任务栏上的图标和菜单(Tray,Menu)


remote.Tray可以为窗口建立一个任务栏的小图标;
remote.Menu可以编写一个菜单;
我们利用这两个组件做一个小图标出来。
首先选用一张小图片,我就用我博客的icon啦;
然后在app/index.js继续添加代码

   const path = require('path');
   const { remote } = require('electron');
   const { Tray, Menu } = remote;
   const trayIcon = new Tray(path.join(__dirname,'logo.ico'));
   const trayMenuTemplate = [
       {
           label: "版本",
           submenu:[
               {
                   label: "electron: " + process.versions.electron
               },
               {
                   label: "chrome: " + process.versions.chrome
               },
               {
                   label: "nodejs: " + process.versions.node
               },
           ]
       },
       {
           label: "退出"
       }
   ];

   const TrayMenu = Menu.buildFromTemplate(trayMenuTemplate);
   trayIcon.setToolTip("右键查看信息");//小图标hover提示
   trayIcon.setContextMenu(TrayMenu);//设置小图标菜单
   Menu.setApplicationMenu(TrayMenu);//顺便可以设置一个应用顶部的菜单

如图

——————————————————————

ipc通讯


为了安全,也为了方便管理,很多东西需要在主进程处理(比如关闭、新建窗口),
那么,如果在渲染进程(应用窗口)中,与主进程进行通讯,使主进程在适当的时候处理事务呢?
那就是通过ipc(信息处理中心)啦;
在主进程中,使用ipcMain,在渲染进程中,使用ipcRenderer
比如,

我们在上一步的“退出”添加功能,使其关闭窗口;
当点击任务小图标的时候,窗口能得到焦点

app/index.js中修改

...
const { remote, ipcRenderer } = require('electron');
...
    {
        label: "退出",
        //click在ApplicationMenu中是不适用的,只能在任务小图标中使用
        click: () => ipcRenderer.send('main-render-quit') //发送信息
    }
...
trayIcon.on('click', () => ipcRenderer.send('main-render-focus'));

在主进程文件index.js中修改:

const { app, BrowserWindow, ipcMain } = require('electron');
...
ipcMain.on('main-render-quit', () => app.quit() );//监听信息,如果有'main-render-quit' send 过来,就执行后面的函数
ipcMain.on('main-render-focus', () => mainWindow.focus() );

复制、保存二维码(右键菜单、粘贴板clipboard、弹窗dialog)

现在我们已经可以生成二维码了,但是如果我们想把二维码发给别人呢?我们需要使用复制功能;

首先引入右键菜单所需的MenuItem, 还有粘贴板clipboard,图片元素 nativeImage,系统文件弹窗dialog,文件系统模块fs
app/index.js中修改

...
const { remote, ipcRenderer, clipboard, nativeImage } = require('electron');
const { Tray, Menu, MenuItem, dialog } = remote; //render进程的dialog需要在remote调用
const fs = require('fs');
...

继续在app/index.js中实现逻辑

//新建一个菜单
var menu = new Menu();
menu.append(new MenuItem({
    label: '复制',
    click: () => {//复制逻辑
        clipboard.writeImage(
            nativeImage.createFromBuffer(imgOfQr)
        );
    }
}));
menu.append(new MenuItem({
    label: '保存',
    click: () => {
        dialog.showSaveDialog({//复制逻辑
            title: '请选择保存路径',
            filters: [
                {name: 'Images', extensions: ['jpg', 'png', 'gif']},
            ]
        }, (win) => {
            fs.writeFile(win, nativeImage.createFromBuffer(imgOfQr).toPng(), (err) => {
                if(err) {
                    console.warn(err);
                }
            });
        });
    }
}));

qrImg.addEventListener('contextmenu', function (e) {
    e.preventDefault();
    menu.popup(remote.getCurrentWindow());//添加菜单
}, false);


——————————————————————

输入框聚焦(按钮监听)


这是一个可有无的小功能,但是为了展示快捷键,还是多一个小功能吧
我现在预想这样一个功能:
按下ctrl+alt+i的时候,输入框获得焦点
为了实现这个功能,我们需要用到按钮监听组件globalShortcut,这个是在主进程监听,所以我们也需要用到ipc

在主进程文件index.js中修改

const {app, BrowserWindow, ipcMain, globalShortcut } = require('electron');
...
app.on('ready', function() {
...
setGlobalShortcuts();
});
function setGlobalShortcuts() {
    globalShortcut.unregisterAll();
    globalShortcut.register('ctrl+alt+i', function () {//j监听按钮
        mainWindow.webContents.send('global-shortcut', 0);//向某个窗口发送信息
    });
}
...

在渲染窗口的文件app/index.js中修改

ipcRenderer.on('global-shortcut', (event, arg) => {
    switch (arg){
        case 0: qrInput.focus();
    }
});

成功!!

结尾

electron官网查看文档,凭着前端经验,就可以做很多事情啦!!