跳至主要內容

Electron

LincZero大约 7 分钟

Electron

目录

[TOC]

介绍

开源:GitHub开源框架,开发产品可商用

前置知识:html、css、JavaScript

平台:跨平台,Window、Mac、Linux

Electron结构:Electron=Chromium+Node.js+Native API

开发产品:VSCode、Atom、slack、wordpress

开发环境搭建

Node.js

去官网下nodejs.org

项目创建

HelloWorld

终端

npm init -y # 初始化,npm install也行?
npm install electron --save-dev # 安装,必须是开发时依赖
npx electron -v # 检查版本,npx是Node5.0版本后才有
# 或./node_modules/.bin/electron -v # 这样检查版本也行
npx electron . # electron是全局安装的化则不需要加npx前缀
# 或./node_modules/.bin/electron # 打开界面

main.js

var electron = require('electron')

var app = electron.app  // 引用app
var BrowserWindow = electron.BrowserWindow // 窗口引用

var mainWindow = null // 生命要打开的窗口

app.on('ready', ()=>{
  mainWindow = new BrowserWindow({
      width:300,
      height:300,
      webPreferences:{nodeIntegration:true} // 写了html才能引入js代码
  })
  mainWindow.loadFile('index.html') // 加载html页面
  mainWindow.on('closed',()=>{ // 监听关闭,不能忘,否则内存占用越来越多
    mainWindow = null
  })
})

运行窗口

npx electron .

进程结构

流程

主进程和渲染进程

main.js是主进程,像其他html导入的index.js这种是渲染进程

一个主进程可延伸出多个渲染进程

渲染进程访问主进程方法

需要使用Remote模块

打开子窗口

渲染进程index2.js:

const BrowserWindow = require('electron').remote.BrowserWindow // 需要remote
window.onload = function(){
    var btn = this.document.querySelector('#button')
    btn.onclicke = ()=>{
        newWin = new BrowserWindow({
            width:500,
            height:500
        })
        newWin.loadFile('demo.html')
        mainWindow.on('closed',()=>{
        	mainWindow = null
		})
    }
}

开发时工具

调试

未打包时,可通过菜单 > View > Toggle Develop Tools(CtrlShift+I)来调试

调试界面和浏览器调试界面差不多

重新编译

等代码编辑后,可通过菜单 > View > Reload(Ctrl+R)来重新编译

而不需要退出再重新npx electron .

但有时会有点问题,即使第一次正常,Reload后也可能变得不正常

创建菜单后开发工具丢失

main.js

// mainWindow = new BrowserWindow({...})之后
mainWindow.webContents.openDevTools // 打开窗口后直接打开调试模式

打包

有electron-packager和electron-builder两种方式实现

electron-packager

electron-builder

功能更丰富,支持平台更多,也支持制动更新。打包出的包更轻量,并可以打包出不暴露源码的setup安装程序

安装依赖

yarn add electron-builder --save-dev // 官方强烈推荐使用yarn安装依赖包,但亲测npm可以

package.json做配置

"build": {
    "appId": "com.study.app",
    "win": {
      "target": ["nsis","zip"]
    },
    "mac": {
      "target": ["dmg","zip"]
    }
  },
  "scripts": {
    "dist": "electron-builder --win --x64"
  },

打包执行npm run dist即可

功能实现

菜单

菜单的创建和绑定事件

menu.js // 菜单文件,在主进程中

const {Menu} = require('electron')
var template = [
    {
        label: '菜单1',
        submenu: [
            {
                label:'子菜单1',
                accelerator: 'ctrl+n', // 快捷键
                click:()=>{} // 事件绑定
            },
            {label:'子菜单2'}
        ]
    },
    {
        label: '菜单2'
    }
]
var m = Menu.buildFromTemplate(template) // 放入模板
Menu.setApplicationMenu(m) // 放入App

main.js // 主进程

var electron = require('electron')

var app = electron.app
var BrowserWindow = electron.BrowserWindow

var mainWindow = null

app.on('ready', ()=>{
  mainWindow = new BrowserWindow({
      width:300,
      height:300
  })
  require('./main/menu.js') // 把菜单文件导入主进程......这种写法可以将菜单的js分离出去!!!!!!
  mainWindow.loadFile('index.html')
  mainWindow.on('closed',()=>{
    mainWindow = null
  })
})

右键菜单

// window.addEventListener('click',()=>{ // 单击事件
//     alert(111)
// })
const {remote} = require('electron')
var rightTemplate = [
    {label:'复制'},
    {label:'粘贴'}
]
var m = remote.Menu.buildFromTemplate(rightTemplate) // 放入模板
window.addEventListener('contextmenu',(e)=>{ // 右击事件
    e.preventDefault() // 阻止默认事件
    m.popup({window:remote.getCurrentWindow()}) // 放入右键事件中
})

Web

通过链接打开浏览器

使用<a>标签默认在窗口程序中打开

如果需要在其他浏览器打开,是要使用shell

demo.js

var {shell} = require('electron')
var aHref = document.querySelector('#aHref')
aHref.onclick = function(e){
    e.preventDefault() // 阻止窗口打开链接的默认行为
    var href = this.getAttribute('href')
    shell.openExternal(href)
}

嵌入网页

嵌入网页用webview和browserView

main.js // 主进程

// 加载html页面后
var BrowserView = electron.BrowserView
var view = new BrowserView()
mainWindow.setBrowserView(view)
view.serBounds({ // 设置属性
    x:0,
    y:120,
    width:1000,
    height:700
})
view.webContent.loadURL('http://baidu.com')

打开网页子窗口

window.open('http://baidu.com')

后面直接接一个html好像也行

对话框

这里原生HTML也能做得到,这里使用的是Electron的API方法

选择文件对话框

选择文件对话框API:

  • 异步dialog.showOpenDialog(基本属性,回调函数),或可以使用then
  • 同步dialog.showOpenDialogSync(基本属性)

基本属性(对象类型)参数表:

属性类型说明
titleString(可选)对话的标题
defaultPathString(可选)默认打开路径
buttonLabelString(可选)确定按钮的自定义标签
filtersList(可选)文件选择过滤器(扩展名筛选)
properties打开文件的属性:文件/文件夹、隐藏文件

demo

const {dialog} = require('electron').remote
var openBtn = document.getElementById('openBtn')

openBtn.onclick = function(){
    dialog.showOpenDialog({
        title: '请选择xxx文件',
        defaultPath: 'C:\\xxx.jpg',
        filters:[
            {name:'img',extensions:['jpg','png']}
        ],
        buttonLabel: '确定选择'
    }).then(result=>{
        let image = document.getElementById('images')
        image.setAttribute("src",result.filePaths[0])
    }).catch(err=>{
        console.log(err)
    })
}

保存文件对话框

保存文件对话框API:

showSaveDialog

同步异步、参数那些和上面差不多

const {dialog} = require('electron').remote
const fs = require('fs') // Node.js的fs模块

var openBtn = document.getElementById('openBtn')
openBtn.onclick = function(){
    dialog.showSaveDialog({
        title: '保存文件'
    }).then(result=>{
        console.log(result)
        fs.writeFileSync(result.filePath,'lalala') // 这里有点问题,选择文件夹要加文件名
    }).catch(err=>{
        console.log(err)
    })
}

消息对话框

API:showMessageBox()

常用参数:

属性类型说明
typeString参数:none、info、error、question、warning
titleString弹出框的标题
messageString(必写)message box的内容
buttonsListAPI返回值为该列表的索引的下标值

Demo

dialog.showMessageBox({
    type: 'warning',
    title: '信息对话框标题',
    message: '信息对话',
    buttons: ['按钮1','按钮2'] // 会返回数组下标
})

网络监控与断网提醒

demo

window.addEventListener('online',function(){ // 注意:刚开始连网时不会触发,需要网络断了后重新连上才会触发
    alert('网络连上了!')
})
window.addEventListener('offline',function(){
    alert('网络断了!')
})

底部信息通知

demo

var option = {
    title: '通知标题',
    body: '通知信息'
}
new window.Notification(option.title,option)

注册全局快捷键

demo

var globalShortcut = electron.globalShortcut
// ...写在app.on(‘ready',()=>{})里
globalShortcut.register('ctrl+e',()=>{...})
let isRegister = globalShortcut.isRegistered('ctrl+e') // 判断,以免热键冲突,返回Bool值

注销快捷键

app.on('will-quit', function(){
    // 注销全局快捷键方法
    globalShortcut.unregister('ctrl+e') //单独注销
    globalShortcut.unregisterAll() // 全部注销
})

剪切板功能

demo

const clipboard = require('electron').clipboard // 剪切板模块,可在渲染进程使用
// ...
clipboard.writeText('需要复制的文本')

数据传递

子窗口向父窗口传递信息

子窗口

window.opener.postMessage('我是子窗口传递过来的信息')

父窗口

window.open('./subWindow.html') // 打开子窗口
// ...
window.addEventLister('message',(msg)=>{
	let mytext = document.querySelect('#mytext')
    console.log(msg.data) // 打印“我是子窗口传递过来的信息”
})

个人总结

事件监听

app事件 - 开始

app.on('ready', ()=>{})

窗口事件监听 - 关闭窗口事件

mainWindow.on('closed',()=>{mainWindow = null})

window监听 - 右击菜单事件

window.addEventListener('contextmenu',(e)=>{})

window监听 - 网络监听

window.addEventListener('online',function(){})
window.addEventListener('offline',function(){})

window监听 - 信息传递

// window.opener.postMessage('我是子窗口传递过来的信息') // 该信息由该代码发起
window.addEventLister('message',(msg)=>{})

electron的子模块

const electron = require('electron') // 主模块,方便下面的子模块引入代码的书写
const app = electron.app // App模块
const BrowserWindow = electron.BrowserWindow // 窗口模块
const BrowserWindow = electron.remote.BrowserWindow // 窗口模块(非主进程)
const Menu = electron.Menu // 菜单模块
const remote = electron.remote // 右键菜单模块
const shell = electron.shell // 脚本模块
const BrowserView = electron.BrowserView // 浏览器视图模块
const dialog = electron.remote.dialog // 对话框模块(非主进程)
const globalShortcut = electron.globalShortcut // 全局快捷键
const clipboard = electron.clipboard // 剪切板模块,可在渲染进程使用

App模块

const app = require('electron').app // app模块
// ...
app.on('ready', ()=>{...})
app.on('will-quit', ()=>{...})

BrowserWindow窗口模块

const BrowserWindow = require('electron').BrowserWindow // BrowserWindow窗口模块
// ...
mainWindow = new BrowserWindow({...}) // 窗口
mainWindow.loadFile('index.html')
mainWindow.webContents.openDevTools
const Menu = require('electron').Menu // Menu菜单模块
//...
var m = Menu.buildFromTemplate([...]) // 放入模板,一般模板写外面
Menu.setApplicationMenu(m) // 放入App

remote右键菜单模块

const remote = require('electron').remote // remote右键菜单模块
// ...
var m = remote.Menu.buildFromTemplate([...]) // 放入模板,一般模板写外面
window.addEventListener('contextmenu',(e)=>{ // 右击事件
    e.preventDefault()
    m.popup({window:remote.getCurrentWindow()}) // 放入右键事件中
})

等等

略...