1. 简介

  • 官网
  • Electron是由GitHub开发,使用 JavaScript,HTML 和 CSS 构建跨平台的桌面应用程序
  • Electron 可以让你使用纯 JavaScript 调用丰富的原生 APIs 来创造桌面应用。你可以把它看作是专注于桌面应用
  • 在PC端混合app开发中,nwjs和electron都是可选的方案,它们都是基于Chromium和Node的结合体, 而electron相对而言是更好的选择方案,它的社区相对比较活跃,bug比较少,文档先对利索简洁。
  • electron 相对来说比 nw.js 靠谱。有一堆成功的案例:Atom 编辑器 2. Slack (那个独角兽公司)3. Visual Studio Code 4. WordPress 等等。。
  • Node. js 的所有 内置模块 都在Electron中可用, 第三方 node 模块中也完全支持 (包括 原生模块 )。
  • Electron 还为开发原生桌面应用程序提供了一些额外的内置模块。 某些模块仅在主进程中可用, 有些仅在渲染进程 (web 页) 中可用, 而有些在这两个进程中都可以使用。

2. 五分钟快速上手

2.1 安装electron

  • npm init
  • cnpm I electron –S
  • npx electron

2.2 配置为入口文件

{
  "name": "electron-demo",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "electron ."
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "electron": "^8.3.0"
  }
}

2.3 创建main.js文件

const electron = require('electron')

const app = electron.app 

app.on('ready', ()=>{
  new electron.BrowserWindow({
    width: 800,
    height: 300
  })
})

2.4创建窗口

app.on('ready', ()=>{
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 500
  })

  mainWindow.loadFile('./index.html')
})

3. 主进程和渲染进程

Electron 运行 package.jsonmain 脚本的进程被称为主进程。 在主进程中运行的脚本通过创建web页面来展示用户界面。 一个 Electron 应用总是有且只有一个主进程。

由于 Electron 使用了 Chromium 来展示 web 页面,所以 Chromium 的多进程架构也被使用到。 每个 Electron 中的 web 页面运行在它的叫渲染进程的进程中。

在普通的浏览器中,web页面无法访问操作系统的原生资源。 然而 Electron 的用户在 Node.js 的 API 支持下可以在页面中和操作系统进行一些底层交互。

ctrl+shift+i打开渲染进程调试

app.on('ready', ()=>{
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 500
  })

  mainWindow.loadFile('./index.html')

  const mainWindow2 = new BrowserWindow({
    width: 800,
    height: 500
  })

  mainWindow2.loadFile('./index2.html')
})

4. 自定义原生菜单

4.1 自定义菜单

const electron = require('electron')

const { app, Menu } = electron
const template = [
  {
    label: '文件',
    submenu: [
      {
        label: '新建窗口'
      }
    ]
  },
  {
    label: '编辑',
    submenu: [
      {
        label: '新建窗口'
      }
    ]
  }
]
const menu = Menu.buildFromTemplate(template)

Menu.setApplicationMenu(menu)

4.2 给菜单定义点击事件

1、点击打开新窗口

submenu: [
  {
    label: '新建窗口',
    click: ()=>{
      const newMainWindow = new BrowserWindow({
        width: 300,
        height: 300
      })
      newMainWindow.loadFile('./new.html')
    }
  }
]

2、点击打开浏览器

const { BrowserWindow, Menu, shell } = require('electron')
const template = [
  {
    label: '文件',
    submenu: [
      {
        label: '文件1',
        click () {
          // 点击打开新窗口
          const mainWindow2 = new BrowserWindow({
            width: 600,
            height: 600
          })
        
          mainWindow2.loadFile('./index.html')
        }
      }
    ]
  },
  {
    label: 'csdn',
    click () {
      // 点击打开浏览器
      shell.openExternal('')
    }
  }
]

4.3 抽离菜单定义

const { BrowserWindow, Menu} = require('electron')
const template = [
  {
    label: '文件',
    submenu: [
      {
        label: '新建窗口',
        click: ()=>{
          const newMainWindow = new BrowserWindow({
            width: 300,
            height: 300
          })
          newMainWindow.loadFile('./new.html')
        }
      }
    ]
  },
  {
    label: '编辑',
    submenu: [
      {
        label: '新建窗口'
      }
    ]
  }
]
const menu = Menu.buildFromTemplate(template)

Menu.setApplicationMenu(menu)
require('./menu')
打开调式

mainWindow.webContents.openDevTools()

4.4 自定义顶部菜单

  • 通过frame创建无边框窗口
const mainWindow = new electron.BrowserWindow({
    frame: false
})
  • 自定义窗口
<div class="header" style="-webkit-app-region: drag;">

</div>
  • icon
const mainWindow = new electron.BrowserWindow({
    width: 1000,
    height: 600,
    webPreferences: {
      nodeIntegration: true
    },
    frame: false,
    icon: './hm.ico'
  })
  • backgroundColor

4.5 定义右键菜单

js>index.js

const { remote } = require('electron')
const template = [
  {
    label: '粘贴'
  },
  {
    label: '赋值'
  }
]
const menu = remote.Menu.buildFromTemplate(template)

window.addEventListener('contextmenu', (e) => {
  console.log(123)
  e.preventDefault()
  menu.popup({ window: remote.getCurrentWindow() })
})

在index.html中引入

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <button>打开新的窗口</button>
  <script src="./js/index.js"></script>
</body>
</html>

能够在html中使用node方法

const mainWindow = new BrowserWindow({
  width: 800,
  height: 500,
  webPreferences: {
    nodeIntegration: true
  }
})

4.6 点页面打开浏览器

  • html
<a id="a1" href="">打开浏览器</a>
  • js
const { shell } = require('electron')
const allA = document.querySelectorAll('a')

allA.forEach(item => {
  item.onclick = function (e) {
    e.preventDefault()
    console.log(item)
    shell.openExternal(item.href)
  }
})

5. 自动刷新页面

  • 安装插件
cnpm install --save-dev electron-reloader
  • 在入口引入插件
const reloader = require('electron-reloader')
reloader(module,{})

6. 拖拽文件进行读取

  • 定义拖拽到指定区域
<div id="drop">
</div>
#drop {
  width: 300px;
  height: 500px;
  background: hotpink;
}
  • 添加拖拽事件获取文件路径
// 添加拖拽
const dropEl = document.querySelector('#drop')
dropEl.addEventListener('drop', function(e) {
  if(e.dataTransfer.files.length === 1) {
    const filePath = e.dataTransfer.files[0].path
  }
})

dropEl.addEventListener('dragover', function (e) {
  e.preventDefault()
})
  • 引入fs模块进行读取
const fs = require('fs')

// 添加拖拽
const dropEl = document.querySelector('#drop')
dropEl.addEventListener('drop', function(e) {
  if(e.dataTransfer.files.length === 1) {
    const filePath = e.dataTransfer.files[0].path
    const fileContent = fs.readFileSync(filePath).toString()
    this.innerText = fileContent
  }
})

dropEl.addEventListener('dragover', function (e) {
  e.preventDefault()
})

7. 打开对话框

7.1 读取文件

  • 定义点击事件
<button onclick="openFile()">打开</button>
  • 定义事件函数
// 打开对话框
function openFile() {
  const res = remote.dialog.showOpenDialogSync({
    title: '选择文件',
    buttonLabel: '哈哈',
    filters: [
      { name: 'Custom File Type', extensions: ['js','html','json'] },
    ]
  })

  const fileContent = fs.readFileSync(res[0]).toString()
  dropEl.innerText = fileContent
}

7.2 保存文件

  • 定义点击事件
<button onclick="saveFile()">保存</button>
  • 事件函数
// 保存对话框
function saveFile() {
  const res = remote.dialog.showSaveDialogSync({
    title: '保存文件',
    buttonLabel: '保存文件',
    filters: [
      { name: 'index', extensions: ['js'] },
    ]
  })
  fs.writeFileSync(res, 'hahhdasdshafsdahjk')
}

8. 消息提示

  • 定义事件
<button onclick="messageBox()">提示</button>
  • 事件函数
// 提示信息
function messageBox() {
  remote.dialog.showMessageBoxSync({
    type: 'none',
    buttons: ['确定'],
    title: '提示消息',
    message: '明天会下雨呦'
  })
}

9. 定义快捷键

9.1 主线程定义

  • 引入
const { app, BrowserWindow, globalShortcut } = require('electron')
  • 在ready中注册快捷键
const { app, BrowserWindow, globalShortcut } = require('electron')

9.2 渲染进程定义

  • 通过remote注册
// 定义快捷键
remote.globalShortcut.register('Ctrl+O', () => {
  console.log('ctrl+o')
})
  • 定义快捷键最大、最小、关闭窗口
globalShortcut.register('Ctrl+T',()=>{
    mainWindow.unmaximize();
  })
  globalShortcut.register('Ctrl+H',()=>{
    mainWindow.close()
  })
  globalShortcut.register('Ctrl+M',()=>{
    mainWindow.maximize()
  })

10. 渲染进程和主线程通讯

  • 定义按钮
<div class="maxWindow no-drag" onclick="maxWindow()"></div>
  • 事件函数
function maxWindow() {
  ipcRenderer.send('max-window')
}
  • 主线程定义事件
ipcMain.on('max-window', () => {
    mainWindow.maximize()
  })
  • 传参
let windowSize = 'unmax-window'
function maxWindow() {
  windowSize = windowSize === 'max-window' ?'unmax-window':'max-window'
  ipcRenderer.send('max-window',windowSize)
}
  • 接收参数
ipcMain.on('max-window', (event,arg) => {
    console.log(arg)
    if(arg === 'unmax-window') return mainWindow.maximize();
    mainWindow.unmaximize()
  })
  • 通过isMaximized判断当前窗口

11. 网络请求

async function getMsg () {
  const res = await fetch('http://127.0.0.1:3006/api/person').then(res=>res.json())
  console.log(res)
}

12 .electron结合框架开发

12.1 结合react

利用react初始化项目
  • npx create-react-app electron-react
  • cd electron-react
  • npm start
安装electron
  • cnpm i electron
  • 添加electron的任务
"main": "main.js",
"scripts": {
   "start": "react-scripts start",
   "build": "react-scripts build",
   "test": "react-scripts test",
   "eject": "react-scripts eject",
   "electron": "electron ."
  },
const {app, BrowserWindow} = require('electron')

function createWindow () {
  // Create the browser window.
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600
  })
  // Open the DevTools.
  // mainWindow.webContents.openDevTools()
}

app.whenReady().then(() => {
  createWindow()
})
  • 加载react项目
mainWindow.loadURL('http://localhost:3000/')

12.2 electron结合vue

同react

13 electron打包

  • 将vue项目打包
  • 修改electron引入的文件
mainWindow.loadFile('./dist/index.html')
  • 安装electron-packager
"packager": "electron-packager ./ HelloWorld --platform=win32 --arch=x64 --out ./outApp --overwrite --icon=./favicon.ico"