Electron - 常用 API 解析

上一篇介绍了 Electron 的架构,今天来了解一下它到底有什麽 API 供我们使用~

Electron API
(图片来源:Electronvue开发实战1

从图可以了解,主进程、渲染进程都各自有可以使用的 API,而有些两边皆可以使用,因为这些功能实在是太多了,接下来就只介绍一些常用的 API

主进程 API

这边介绍的 API 只有主进程能用,无法在渲染进程使用

app

app 操控整个应用程序的生命周期,常会用来监听与整个应用程序的重要事件

// main.js

const { app } = require('electron')
app.on('window-all-closed', function () {
  app.quit()
})

event

  • ready:完成初始化时触发
  • window-all-closed:所有视窗关闭时触发
  • activate:唤醒应用程序时触发(macOS)
  • browser-window-created:视窗被创建时触发
  • browser-window-focus:视窗被关注时触发
  • browser-window-blur:视窗被取消关注时触发

method

  • app.quit():关闭所有视窗
  • app.exit():退出所有视窗,不会询问用户
  • app.whenReady():初始化後执行(回传 Promise
  • app.hide():隐藏所有视窗(macOS)
  • app.show():显示所有视窗(macOS)
  • app.requestSingleInstanceLock():视窗是否成功锁定为单一视窗(回传 Boolean
// main.js

const { app } = require('electron')
let myWindow = null
const gotTheLock = app.requestSingleInstanceLock() // 锁定视窗,并记录回传值
if (!gotTheLock) {
  // 开启第二个视窗时无法成功锁定,关闭视窗
  app.quit()
} else {
  // 开启第二个视窗时触发,将第一个视窗还原并关注
  // 此事件为第一个视窗发出
  app.on('second-instance', (event, commandLine, workingDirectory) => {
    if (myWindow) {
      if (myWindow.isMinimized()) myWindow.restore()
      myWindow.focus()
    }
  })
  
  // 正常开启视窗,并储存实例
  app.whenReady().then(() => {
    // 如果 createWindow 为 Promise,则需使用 than 或 async/await
    myWindow = createWindow()
  })
}

BrowserWindow

BrowserWindow 用来建立一个视窗,有许多外观与功能的重要设定,也能监听每个视窗的相关事件

options - 建立视窗参数

// main.js

const { BrowserWindow } = require('electron')
const path = require('path')
// 以下没特别注记即为预设值
const win = new BrowserWindow({
  width: 800, // 宽度
  height: 600, // 高度
  x: 0, // 左方偏移量,预设置中
  y: 0, // 上方偏移量,预设置中
  useContentSize: false, // 设定窗口宽高是否包含框架与 Menu
  minWidth: 0, // 最小宽度
  minHeight: 0, // 最小高度
  maxWidth: 1000, // 最大宽度,预设无限制
  maxHeight: 1000, // 最大高度,预设无限制
  resizable: true, // 可否调整视窗大小
  movable: true, // 可否移动视窗
  minimizable: true, // 可否最小化
  maximizable: true, // 可否最大化
  closable: true, // 可否点击关闭按钮
  alwaysOnTop: false, // 视窗是否总是在顶部
  fullscreen: false, // 视窗是否全萤幕显示
  fullscreenable: true, // 可否将视窗全萤幕
  Kiosk: false, // 视窗是否开启 Kiosk 模式
  title: 'Electron', // 视窗标题
  icon: './images/icon.png', // 视窗框架图示
  show: true, // 是否显示视窗
  frame: false, // 是否隐藏框架 与 Menu
  parent: null, // 父视窗
  disableAutoHideCursor: false, // 视窗内是否隐藏鼠标
  autoHideMenuBar: false, // 是否隐藏 Menu(按下 Alt 可显示)
  backgroundColor: '#FFF', // 背景颜色
  hasShadow: true, // 视窗是否有阴影
  opacity: 0, // 视窗初始不透明度
  darkTheme: false, // 视窗是否使用深色模式
  transparent: false, // 视窗是否透明(frame 为 true 才有作用)
  webPreferences: {
    devTools: true, // 是否开启 devtools
    nodeIntegration: false, // 渲染进程是否可访问 Node.js
    preload: path.join(__dirname, 'preload.js'), // preload.js 文件位置
    enableRemoteModule: false, // 是否启用 remote 模块
    zoomFactor: 1.0, // 窗口缩放系数
    webSecurity: true, // 是否开启同源政策(关闭之後页面才可以打 API)
    webgl: true, // 是否启用 WebGL
    plugins: false, // 是否启用插件
    experimentalFeatures: false, // 是否启用 Chromium 实验功能
    backgroundThrottling: true, // 是否在背景运行
  }
})
win.loadURL('https://github.com')

event

// main.js

const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
win.on('close', (e) => {
  // do something...
})
  • close:视窗将要关闭时触发
  • blur:视窗失去焦点时触发
  • focus:视窗获得焦点时触发
  • show:视窗显示时触发
  • hide:视窗隐藏时触发
  • ready-to-show:视窗可显示时触发
  • maximize:视窗最大化时触发
  • unmaximize:视窗退出最大化时触发
  • minimize:视窗退出最小化时触发
  • restore:视窗还原最小化时触发
  • will-resize:调整视窗大小前触发
  • resize:调整视窗大小时触发
  • resized:调整视窗大小後触发
  • will-move:移动视窗前触发
  • move:移动视窗时触发
  • moved:移动视窗後触发
  • enter-full-screen:视窗进入全萤幕时触发
  • leave-full-screen:视窗退出全萤幕後触发

method - 直接调用

// main.js

const { BrowserWindow } = require('electron')
BrowserWindow.getAllWindows()
  • BrowserWindow.getAllWindows():获取一个包含所有视窗实例的阵列
  • BrowserWindow.getFocusedWindow():获取正在关注的视窗实例
  • BrowserWindow.fromId(id):获取指定 id 的视窗实例

method - 操作实例

// main.js

const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 1500 })
win.destroy()
  • win.destroy():销毁视窗,仅会发出 closed 事件
  • win.close():关闭视窗
  • win.show():显示视窗
  • win.hide():隐藏视窗
  • win.maximize():视窗最大化
  • win.minimize():视窗最小化
  • win.restore():视窗还原最小化
  • win.setFullScreen(Boolean):设定视窗是否全屏
  • win.setSize(width, height):设定视窗宽高
  • win.setContentSize(width, height):设定视窗宽高(不含框架与 Menu)
  • win.moveTop():将视窗移至最上面
  • win.center():将视窗移至中间
  • win.setPosition(x, y):设定视窗位置
  • win.setTitle(title):设定标题
  • win.flashFrame(Boolean):设定视窗是否闪烁
  • win.loadURL(url):视窗载入该 url
  • win.loadFile(filePath):视窗载入该档案
  • win.reload():重新载入当前网页

优化小技巧

这边官方提到两个开启视窗的优化小技巧

  1. 先将页面隐藏,等视窗读取完成时再将其显示出来
// main.js

const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ show: false })
win.once('ready-to-show', () => {
  win.show()
})
  1. 将背景颜色设为与自己应用程序相近或一样的背景色
// main.js

const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ backgroundColor: '#2e2c29' })
win.loadURL('https://github.com')

webContents

webContentsBrowserWindow 相当雷同,建立视窗後若需改变该视窗设定则可使用此方法,另外也有一些更细微的操作

method - 直接调用

// main.js

const { webContents } = require('electron')
webContents.getAllWebContents()
  • webContents.getAllWebContents():获取一个所有视窗的 Array
  • webContents.getFocusedWebContents():获取正在关注的视窗物件
  • webContents.fromId(id):获取指定 id 的视窗物件

method - 操作实例

// main.js

const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 1500 })
win.webContents.loadURL('http://github.com')
  • win.webContents.loadURL(url):视窗载入该 url
  • win.webContents.loadFile(filePath):视窗载入该档案
  • win.webContents.reload():重新载入当前网页
  • win.webContents.reloadIgnoringCache():重新载入当前网页(忽略快取)
  • win.webContents.getURL():获取当前网页网址
  • win.webContents.getTitle():获取当前网页标题
  • win.webContents.clearHistory():清除历史纪录
  • win.webContents.goBack():上一页
  • win.webContents.goForward():下一页
  • win.webContents.goToIndex(index):导航到该索引索面
  • win.webContents.getUserAgent():获取此网页用户代理
  • win.webContents.getZoomFactor():获取当前缩放系数
  • win.webContents.setZoomFactor(factor):设定缩放系数,原始为 1.0
  • win.webContents.openDevTools():打开 devtools
  • win.webContents.closeDevTools():关闭 devtools
  • win.webContents.copy():复制
  • win.webContents.cut():剪下
  • win.webContents.paste():贴上
  • win.webContents.undo():复原
  • win.webContents.redo():重做
  • win.webContents.capturePage([x, y, width, height]):网页截图(回传 Promise
  • win.webContents.send(channel, ...args):同 ipcMain.send
  • win.webContents.startDrag({file, icon}):操作拖动文件
  • win.webContents.printToPDF(options):将网页截图存成 PDF
// main.js

const { BrowserWindow } = require('electron')
const fs = require('fs') // 档案操作
const path = require('path') // 路径操作
const os = require('os') // 系统操作

const win = new BrowserWindow({ width: 800, height: 600 })
win.loadURL('http://github.com')
// loading 完成之後执行
win.webContents.on('did-finish-load', () => {
  win.webContents.printToPDF({}).then(data => {
    // 设定路径为桌面上的 demo.pdf
    const pdfPath = path.join(os.homedir(), 'Desktop', 'demo.pdf')
    // 将档案创建在该路径
    fs.writeFile(pdfPath, data, (error) => {
      if (error) throw error
    })
  }).catch(error => {
    // catch error
  })
})

Menu

Menu 用来建立与设定选单,可直接建立上方工具列的选单,或是其他地方的内容选单

method - 直接调用

// main.js

const { Menu } = require('electron')
const isMac = process.platform === 'darwin'
// 设定 Menu 样板(Windows 与 MacOS 分开设定)
const template = [
  ...(isMac ? [{
    label: 'A-Menu',
    submenu: [
      { role: 'quit' }
    ]
  }] : [{
    label: 'B-Menu',
    submenu: [
      { role: 'undo' },
      { type: 'separator' },
      { label: '关闭', role: 'quit' }
    ]
  }])
]
// 用样板建立一个选单
const menu = Menu.buildFromTemplate(template)
// 设定应用程序顶部选单
Menu.setApplicationMenu(menu)
  • Menu.buildFromTemplate(template):建构一个选单实例
  • Menu.setApplicationMenu(menu):设定顶部选单

method - 操作实例

// main.js

const { ipcMain, BrowserWindow, Menu } = require('electron')

ipcMain.on('click-right', () => {
  // 设定 Menu 样板
  const template = [
    {
      label: 'B-Menu',
      submenu: [
        { role: 'undo' },
        { type: 'separator' },
        { label: '关闭', role: 'quit' }
      ]
    }
  ]
  // 用样板建立一个选单
  const menu = Menu.buildFromTemplate(template)
  // 显示弹出选单
  menu.popup(BrowserWindow.getFocusedWindow())
})
  • menu.popup([options]):显示弹出选单
  • menu.closePopup([browserWindow]):关闭弹出选单
  • menu.append(menuItem):将 menuItem 插入选单最後方
  • menu.insert(pos, menuItem):将 menuItem 插入指定位置

建立选单 template 可以参考官方文件

优化小技巧

如果想要客制化自己的 Menu,可以将 Menu 隐藏,并自己使用刻一个,不过要让自己的视窗可以拖拉记得加上 CSS 属性 -webkit-app-region: drag,但是不要覆盖到功能按钮,否则按钮会失效

<div class="menu">
  <div class="drag">
    <img class="icon" src="./icon.png">
    <span>title</span>
  </div>
  <button><img class="icon" src="./minimiz.png"></button>
  <button><img class="icon" src="./maximiz.png"></button>
  <button><img class="icon" src="./close.png"></button>
</div>
.drag {
  -webkit-app-region: drag;
}

Tray

Tray 是右下角的图示与功能,使用 Menu 建立选单,须於初始化後调用

event

// main.js

const { Tray } = require('electron')
const tray = new Tray()
tray.on('click', (e) => {
  // do something...
})
  • click:图示选单被左键点击时触发
  • right-click:图示选单被右键点击时触发
  • double-click:图示选单被双击时触发

method

// main.js

const { app, Menu, Tray } = require('electron')
let tray = null

app.whenReady().then(() => {
  // 设定 icon 路径
  const tray = new Tray('./images/icon.png')
  // 设定选单样板
  const contextMenu = Menu.buildFromTemplate([
    { label: 'Item1', click: () => { console.log('click') } },
    { label: 'Item2' },
    { label: 'Item3', type: 'radio', checked: true },
    { label: 'Item4', type: 'radio' }
  ])
  // 右下角 icon 被 hover 时的文字
  tray.setToolTip('This is my application.')
  // 设定定应用程序右下角选单
  tray.setContextMenu(contextMenu)
})
  • tray.destroy():销毁图示选单
  • tray.setToolTip(toolTip):设定图示选单被 hover 时的样式
  • tray.displayBalloon(options):设显示一个通知(Windows)
    • icon:图示路径
    • iconTypenoneinfowarningerrorcustom,预设为 custom
    • title:标题(必填)
    • content:内容(必填)
    • largeIcon:是否启用大图示(Boolean),预设为 true
    • noSound:是否播放音效(Boolean),预设为 false
    • respectQuietTime:勿扰模式不显示通知(Boolean),预设为 false
  • tray.removeBalloon():移除通知(Windows)

建立选单 template 可以参考官方文件

Notification

Notification 用来建立一个系统通知,使用 new Notification(options) 建立一个通知实例,须於初始化後调用

options

// main.js

const myNotification = new Notification({
  title: '标题',
  subtitle: '副标题',
  body: '内容',
  silent: true,
  icon: './images/icon.png',
  timeoutType: 'default'
})
  • title:标题(必填)
  • body:内容(必填)
  • subtitle:副标题(macOS)
  • silent:是否发出音效(Boolean)
  • icon:图示路径
  • timeoutType:通知消失时间,值为 defaultnever

event

// main.js

app.whenReady().then(() => {
  const myNotification = new Notification()
  myNotification.on('show', (e) => {
    // do something...
  })
})
  • show:通知显示时触发
  • click:通知被点击时触发
  • close:通知关闭时触发

method

// main.js

app.whenReady().then(() => {
  const myNotification = new Notification({
    title: '标题',
    body: '内容'
  })
  myNotification.show()
})
  • Notification.show():显示通知
  • Notification.close():关闭通知

通知这边因为各系统都有很多毛,所以如果没有显示请参考官方文件

globalShortcut

globalShortcut 用来自定义快捷键,须於初始化後调用

method

// main.js

const { app, globalShortcut } = require('electron')

app.whenReady().then(() => {
  // 注册快捷键 CommandOrControl + 0
  const ret = globalShortcut.register('CommandOrControl+0', () => {
    // do something...
  })
  // 返回 Boolean,用於检查快捷键是否注册成功
  globalShortcut.isRegistered('CommandOrControl+0')
})

app.on('will-quit', () => {
  // 取消注册的快捷键 CommandOrControl + 0
  globalShortcut.unregister('CommandOrControl+0')
  // 取消所有注册的快捷键
  globalShortcut.unregisterAll()
})
  • globalShortcut.register(accelerator, callback):注册快捷键
  • globalShortcut.unregister(accelerator):注消快捷键
  • globalShortcut.registerAll(accelerator, callback):一次注册多个快捷键,accelerator 为阵列
  • globalShortcut.unregisterAll():注消所有快捷键

可定义的 accelerator 请参考官方文件

dialog

dialog 为弹出视窗,用来开启档案选择视窗或讯息弹出视窗等等

method - 档案类型

// main.js

const { dialog } = require('electron')
dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] })
  • dialog.showOpenDialogSync(options):打开档案的弹窗,等待选取档案并返回
  • dialog.showOpenDialog(options):打开档案的弹窗(返回一个 Promise
  • dialog.showSaveDialogSync(options):储存档案的弹窗,等待选取档案并返回
  • dialog.showSaveDialog(options):储存档案的弹窗(返回一个 Promise

options - 档案类型

  • title:标题
  • defaultPath:预设位置
  • buttonLabel:确定按钮的文字
  • filters:可限制档案类型
{
  filters: [
    { name: 'Images', extensions: ['jpg', 'png', 'gif'] },
    { name: 'Movies', extensions: ['mkv', 'avi', 'mp4'] },
    { name: 'Custom File Type', extensions: ['as'] },
    { name: 'All Files', extensions: ['*'] }
  ]
}
  • properties:其他功能,阵列里面放以下字串
    • openFile:可选择文件
    • openDirectory:可选择资料夹
    • multiSelections:可选择多个

method - 对话框类型

// main.js

const { dialog } = require('electron')
dialog.showMessageBox({ type: 'info', title: '标题', message: '内容' })
  • dialog.showMessageBoxSync(options):讯息的弹窗,等待点选并返回
  • dialog.showMessageBox(options):讯息的弹窗(返回一个 Promise
  • dialog.showErrorBox(title, content):错误视窗

options - 对话框类型

  • type:类型,noneinfoerrorquestionwarning
  • buttons:按钮文字,一个里面为字串的阵列,选择後回传索引
  • defaultId:预设选择的按钮索引
  • title:讯息标题
  • message:讯息内容
  • detail:讯息详细文字
  • checkboxLabel:checkbox 的文字
  • checkboxChecked:checkbox 预设值
  • icon:显示的图示
  • cancelId:取消按钮的索引数,Esc 时返回此索引

优化小技巧

我们如果设定视窗 alwaysOnTop 时会发现,视窗将 dialog 盖住了,这时候可以用以下方法

// main.js

import { BrowserWindow, dialog } from 'electron'
// 创建另外一个 alwaysOnTop 的视窗,且不显示於画面
const win = new BrowserWindow({ show: false, alwaysOnTop: true })
// 在该视窗显示 dialog,并在回传後将视窗销毁
dialog.showMessageBox(win, { type: 'info', title: '标题', message: '内容' }).then(() => {
  win.destroy()
})

主进程与渲染进程 API

这边介绍的 API 在主进程能用,在渲染进程也可以使用,可以将值写入全域,以便在 renderer.js 使用

// preload.js

const { clipboard, shell } = require('electron')
window.clipboard = clipboard
window.shell = shell

clipboard

clipboard 就是剪贴簿的功能,可记录文字、HTML、图片等等

method

// main.js

const { clipboard } = require('electron')
clipboard.availableFormats([ 'text/plain', 'text/html' ])
clipboard.writeText('范例字串', 'selection')
console.log(clipboard.readText('selection'))
  • clipboard.writeText(text):将文字写入剪贴簿
  • clipboard.readText():读取剪贴簿的文字
  • clipboard.writeHTML(markup):将 html 写入剪贴簿
  • clipboard.readHTML():读取剪贴簿的 html
  • clipboard.writeImage(image):将图片写入剪贴簿
  • clipboard.readImage():读取剪贴簿的图片
  • clipboard.writeRTF(text):将 RTF 写入剪贴簿
  • clipboard.readRTF():读取剪贴簿的 RTF
  • clipboard.availableFormats([type]):定义剪贴簿可用格式
  • clipboard.clear():清除剪贴簿内容
  • clipboard.write(data):可一次写入多笔资讯
    • text:文字
    • html:html
    • image:图片
    • rtf:RTF
clipboard.write({
  text: 'test',
  html: '<b>Hi</b>',
  rtf: '{\\rtf1\\utf8 text}',
})

shell

shell 可以使用预设的应用程序开启档案,常用在用浏览器开启档案

method

// main.js

const { shell } = require('electron')
shell.openExternal('https://github.com')
  • shell.showItemInFolder(fullPath):打开该文件所在目录并选取该文件
  • shell.openPath(path):使用预设方式打开该文件
  • shell.openExternal(url):使用预设浏览器打开该网址
  • shell.moveItemToTrash(fullPath):删除该档案
  • shell.beep():播放提示音

nativeImage

nativeImage 是一个包装图片的物件,Electron 内许多回传图片都是此类型

// main.js

const { BrowserWindow, Tray, clipboard } = require('electron')
// 以下返回的皆为 nativeImage 物件
const appIcon = new Tray('/Users/somebody/images/icon.png')
const win = new BrowserWindow({ icon: '/Users/somebody/images/window.png' })
const image = clipboard.readImage()

method - 直接调用

  • nativeImage.createFromPath(path):依路径建立一个 nativeImage 物件
  • nativeImage.createFromBitmap(buffer, options):依档案建立一个 nativeImage 物件
  • nativeImage.createFromBuffer(buffer, options):依档案建立一个 nativeImage 物件
  • nativeImage.createFromDataURL(dataURL):依 dataURL 建立一个 nativeImage 物件
  • nativeImage.createFromPath(path):依路径建立一个 nativeImage 物件

method - 操作实例

  • image.toPNG(path):返回 Buffer
  • image.toJPEG(quality):返回 Buffer,quality 为 0 ~ 100
  • image.toBitmap(path):返回 Buffer
  • image.toDataURL(path):返回 String
  • image.getBitmap(path):返回 Buffer

渲染进程 API

这边介绍的 API 仅在渲染进程能用,无法在主进程使用

remote

remote 是很特别的方法,他的作用是为了让渲染进程使用部分主进程的功能,使用方法如下

// main.js

const { BrowserWindow } = require('electron')
const path = require('path')

const win = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    preload: path.join(__dirname, 'preload.js'),
    enableRemoteModule: true // 启用 remote 模块
  }
})
win.loadURL('https://github.com')
// preload.js

const { dialog } = require('electron').remote
window.dialog = dialog
// renderer.js

window.dialog.showErrorBox('标题', '内容')

method

  • remote.require(module):载入相对路径模块
  • remote.getCurrentWindow():回传当前视窗实例
  • emote.getCurrentWebContents():回传当前视窗内容实例
// preload.js

const foo = require('electron').remote.require('./foo')
require('electron').remote.getCurrentWindow().on('close', () => {
  // do something...
})

结语

读文件真的太苦了


<<:  前端工程学习日记第17天

>>:  [Golang]同步工具-sync包的原子操作(上)-心智图总结

30天打造品牌特色电商网站 Day.21 图片展示设计

昨天跟大家介绍了网页首图的媒材,那今天针对图片展示的部分来做一个分享,整理出几个常见的网页排版,可以...

[ JS个人笔记 ] const、let、var的区别—DAY3

主要区别 var: 变数未宣告前使用,会出现undefined var为函式作用域(function...

[Day16]ISO 27001 标准:持续改善

这是 ISO 27001 的最後一个章节,要表达的精神很简单! 就是如果有人发现【机房的门没有关】,...

Day 07: Creational patterns - Abstract Factory

目的 假如产品之间有可以负责联系的元素,那依赖该元素找出共同点後建立关联,进而减少工厂的数量,却可以...

Day3 资料储存 - block storage优缺点及场景

优缺点 优点 Block storage最大的优点就是他使得计算与储存分离,我们能轻易地透过LUN ...