Electron
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) // 放入Appmain.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(基本属性) 
基本属性(对象类型)参数表:
| 属性 | 类型 | 说明 | 
|---|---|---|
| title | String(可选) | 对话的标题 | 
| defaultPath | String(可选) | 默认打开路径 | 
| buttonLabel | String(可选) | 确定按钮的自定义标签 | 
| filters | List(可选) | 文件选择过滤器(扩展名筛选) | 
| 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()
常用参数:
| 属性 | 类型 | 说明 | 
|---|---|---|
| type | String | 参数:none、info、error、question、warning | 
| title | String | 弹出框的标题 | 
| message | String(必写) | message box的内容 | 
| buttons | List | API返回值为该列表的索引的下标值 | 
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.openDevToolsMenu菜单模块
const Menu = require('electron').Menu // Menu菜单模块
//...
var m = Menu.buildFromTemplate([...]) // 放入模板,一般模板写外面
Menu.setApplicationMenu(m) // 放入Appremote右键菜单模块
const remote = require('electron').remote // remote右键菜单模块
// ...
var m = remote.Menu.buildFromTemplate([...]) // 放入模板,一般模板写外面
window.addEventListener('contextmenu',(e)=>{ // 右击事件
    e.preventDefault()
    m.popup({window:remote.getCurrentWindow()}) // 放入右键事件中
})等等
略...