iT邦幫忙

0

Electron - 常用 API 解析

Ares 2020-11-25 13:17:398235 瀏覽
  • 分享至 

  • twitterImage
  •  

上一篇介紹了 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...
})

結語

讀文件真的太苦了


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Tree
iT邦新手 3 級 ‧ 2020-12-19 15:44:34

Ares image.toDataURL(path) 的返回值是 String 歐!


很詳細的翻譯文件 /images/emoticon/emoticon12.gif

Ares iT邦研究生 3 級 ‧ 2020-12-20 00:46:23 檢舉

已修正~感謝!

我要留言

立即登入留言