Electron-d-2.0

Electron

本篇文章接上一篇文章,详细讲解主进程和渲染进程一些常用的API

主进程API

1.App+BrowserWindow

App事件:
(1)Before-quit
  • event Event #返回

在程序关闭窗口前触发(macOS不是关闭窗口触发,而是关闭程序)

**注:**在 Windows 系统中,如果应用程序因系统关机/重启或用户注销而关闭,那么这个事件不会被触发。

代码以及程序演示:

(2)browser-window-blur
  • event Event #返回
  • window BrowserWindow #返回

当一个 browserWindow (窗口)失去焦点时触发。当我们鼠标点击窗口以外的地方就会失焦。

代码以及程序演示:

(3)browser-window-focus
  • event Event #返回
  • window BrowserWindow #返回

当一个 browserWindow 获得焦点时触发。

代码以及程序演示:

(4)quit
  • event Event #返回
  • exitCode Integer #返回

在应用程序退出时发出。

**注:**在 Windows 系统中,如果应用程序因系统关机/重启或用户注销而关闭,那么这个事件不会被触发。

代码以及程序演示:

(5)window-all-closed

当所有的窗口都被关闭时触发。

如果你没有监听此事件并且所有窗口都关闭了,默认的行为是控制退出程序;但如果你监听了此事件,你可以控制是否退出程序。 如果用户按下了 Cmd + Q,或者开发者调用了 app.quit(),Electron 会首先关闭所有的窗口然后触发 will-quit 事件,在这种情况下 window-all-closed事件不会被触发。

代码以及程序演示:

方法:

由于各种app.方法使用频率都差不多,那么我们根据需要看官方文档吧(也比较容易看懂)

[App.方法 文档]: “https://www.electronjs.org/zh/docs/latest/api/app#方法

BrowserWindow:

BrowserWindow 类暴露了各种方法来修改应用窗口的外观和行为

(1)优雅的打开窗口

ready-to-show 事件

在加载页面时,渲染进程第一次完成绘制时,如果窗口还没有被显示,渲染进程会发出 ready-to-show 事件 。 在此事件后显示窗口将没有视觉闪烁:(不会有白屏出现,但如果绘制没有完成,窗口出现的时间也会延长,根据业务需求来选择是否要选择这种优雅的打开窗口方式)

这个事件通常在 did-finish-load 事件之后发出,但是页面有许多远程资源时,它可能会在 did-finish-load之前发出事件。

backgroundColor属性

对于一个复杂的应用,ready-to-show 可能发出的太晚,会让应用感觉缓慢。 在这种情况下,建议立刻显示窗口,并使用接近应用程序背景的 backgroundColor

建议 设置 backgroundColorready-to-show 事件一起用,以使应用感觉更接近原生。

//backgroundColor有效值
const win = new BrowserWindow()
win.setBackgroundColor('hsl(230, 100%, 50%)')
win.setBackgroundColor('rgb(255, 145, 145)')
win.setBackgroundColor('#ff00a3')
win.setBackgroundColor('blueviolet')
(2)父子窗口&&模态窗口

父子窗口:

通过使用 parent 选项,你可以创建子窗口:

const { BrowserWindow } = require('electron')

const top = new BrowserWindow()
const child = new BrowserWindow({ parent: top })
child.show()
top.show()

child 窗口将总是显示在 top 窗口的顶部.

模态窗口

模态窗口是禁用父窗口的子窗口,创建模态窗口必须设置 parentmodal 选项:

const { BrowserWindow } = require('electron')

const child = new BrowserWindow({ parent: top, modal: true, show: false })
child.loadURL('https://github.com')
child.once('ready-to-show', () => {
  child.show()
})

(3)BrowserWindow属性

这个BrowserWindow属性 比较多,而且都是设置窗口的一些属性,也是不难理解,我们就对照我们的官方文档来学习吧!

[BrowserWindow属性]: “https://www.electronjs.org/zh/docs/latest/api/browser-window#new-browserwindowoptions

(4)webContents

did-finish-load 事件

导航完成时触发,即选项卡的旋转器将停止旋转,并指派onload事件后。

[webContents类实例事件]: “https://www.electronjs.org/zh/docs/latest/api/web-contents#类-webcontents

(5)保存窗口状态

当我们使用桌面程序的时候,那么我们有时候希望我们关闭程序再次打开程序的时候,程序的界面和状态能够是我们关闭前的样子,不希望再去重新设置。那我们就需要一个包electron-win-state

安装这个包

npm i electron-win-state -S

我们可以在npmjs官网上找到这个包,去看它的说明文档

根据使用说明,我们代码如下:

我们发现报错了,WinState is not a constructor

当我们打印一下WinState看看什么情况

const WinState = require('electron-win-state')
console.log(WinState)

发现没有直接引入WinState,我们修改一下

const WinState = require('electron-win-state').default 

现在就没报错了。

但是我们发现,虽然安装了这个包,但是我们程序的状态还是没有改变,这就很奇怪了,其实,是我们自己已经给窗口设置了自定义宽高,覆盖了。我们也缺了一句代码;

 winState.manage(win)

现在我们的状态保存就没问题了。当我们关闭窗口再次打开的时候就是关闭之前的样子了。

2.dialog

这些具体参数请看官方文档,下面几个方法返回一个promise对象

(1)dialog.showOpenDialog([browserWindow, ]options)
(2)dialog.showSaveDialog([browserWindow, ]options)
(3)dialog.showMessageBox([browserWindow, ]options)

[dialog文档]: “https://www.electronjs.org/zh/docs/latest/api/dialog#dialogshowopendialogsyncbrowserwindow-options

3.快捷键(globalShortcut)

在应用程序没有键盘焦点时,监听键盘事件。

globalShortcut 模块可以在操作系统中注册/注销全局快捷键, 以便可以为操作定制各种快捷键。

注意: 快捷方式是全局的; 即使应用程序没有键盘焦点, 它也仍然在持续监听键盘事件。 在 app 模块的 ready 事件就绪之前,这个模块不能使用。

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

app.whenReady().then(() => {
  // 注册一个'CommandOrControl+X' 快捷键监听器
  const ret = globalShortcut.register('CommandOrControl+X', () => {
    console.log('CommandOrControl+X is pressed')
  })

  if (!ret) {
    console.log('registration failed')
  }

  // 检查快捷键是否注册成功
  console.log(globalShortcut.isRegistered('CommandOrControl+X'))
})

app.on('will-quit', () => {
  // 注销快捷键
  globalShortcut.unregister('CommandOrControl+X')

  // 注销所有快捷键
  globalShortcut.unregisterAll()
})

方法

globalShortcut 模块具有以下方法:

(1)globalShortcut.register(accelerator, callback)
  • accelerator Accelerator
  • callback Function

返回boolean - 快捷键注册是否成功

注册 accelerator 的全局快捷键。 当用户按下注册快捷键时, callback 会被调用。

如果指定的快捷键已经被其他应用程序注册掉, 调用会默默失败。 该特性由操作系统定义,因为操作系统不希望多个程序的全局快捷键互相冲突。

在 macOS 10.14 Mojave 下面,如果 app 没有被授权为可信任使用的客户端,那么下列快捷键会注册失败:

  • “Media Play/Pause”
  • “Media Next Track”
  • “Media Previous Track”
  • “Media Stop”
(2)globalShortcut.registerAll(accelerators, callback)
  • accelerators string[] - an array of Accelerators.
  • callback Function

注册多个全局快捷键。 当用户按下注册快捷键时, callback 会被调用。

如果定义的快捷键已经被其他应用占用,这个调用会失效。 该特性由操作系统定义,因为操作系统不希望多个程序的全局快捷键互相冲突。

在 macOS 10.14 Mojave 下面,如果 app 没有被授权为可信任使用的客户端,那么下列快捷键会注册失败:

  • “Media Play/Pause”
  • “Media Next Track”
  • “Media Previous Track”
  • “Media Stop”
(3)globalShortcut.isRegistered(accelerator)
  • accelerator Accelerator

Returns boolean - 表示 accelerator 全局快捷键是否注册成功

当快捷键已经被其他应用程序注册时, 此调用依然将返回 false。 该特性由操作系统定义,因为操作系统不希望多个程序的全局快捷键互相冲突。

(4)globalShortcut.unregister(accelerator)
  • accelerator Accelerator

注销 accelerator 的全局快捷键。

(5)globalShortcut.unregisterAll()

注销所有的全局快捷键(清空该应用程序的所有全局快捷键)。

4.菜单(Menu)

我们这举个例子:

//一个简单的菜单模板
const { app, Menu } = require('electron')

const isMac = process.platform === 'darwin'//判断是不是macOS
//role:菜单选项
const template = [
  // { role: 'appMenu' }
  ...(isMac ? [{
    label: app.name,//我们程序名称
    submenu: [
      { role: 'about' },
      { type: 'separator' },//分割线
      { role: 'services' },
      { type: 'separator' },//分割线
      { role: 'hide' },
      { role: 'hideOthers' },
      { role: 'unhide' },
      { type: 'separator' },//分割线
      { role: 'quit' }
    ]
  }] : []),
  // { role: 'fileMenu' }
  {
    label: 'File',
    submenu: [
      isMac ? { role: 'close' } : { role: 'quit' }
    ]
  },
  // { role: 'editMenu' }
  {
    label: 'Edit',
    submenu: [
      { role: 'undo' },
      { role: 'redo' },
      { type: 'separator' },//分割线
      { role: 'cut' },
      { role: 'copy' },
      { role: 'paste' },
      ...(isMac ? [
        { role: 'pasteAndMatchStyle' },
        { role: 'delete' },
        { role: 'selectAll' },
        { type: 'separator' },//分割线
        {
          label: 'Speech',
          submenu: [
            { role: 'startSpeaking' },
            { role: 'stopSpeaking' }
          ]
        }
      ] : [
        { role: 'delete' },
        { type: 'separator' },//分割线
        { role: 'selectAll' }
      ])
    ]
  },
  // { role: 'viewMenu' }
  {
    label: 'View',
    submenu: [
      { role: 'reload' },
      { role: 'forceReload' },
      { role: 'toggleDevTools' },
      { type: 'separator' },//分割线
      { role: 'resetZoom' },
      { role: 'zoomIn' },
      { role: 'zoomOut' },
      { type: 'separator' },//分割线
      { role: 'togglefullscreen' }
    ]
  },
  // { role: 'windowMenu' }
  {
    label: 'Window',
    submenu: [
      { role: 'minimize' },
      { role: 'zoom' },
      ...(isMac ? [
        { type: 'separator' },//分割线
        { role: 'front' },
        { type: 'separator' },//分割线
        { role: 'window' }
      ] : [
        { role: 'close' }
      ])
    ]
  },
  {
    role: 'help',
    submenu: [
      {
        label: 'Learn More',
        click: async () => {
          //定义自己的菜单方法
          const { shell } = require('electron')
          await shell.openExternal('https://electronjs.org')
        }
      },
      {
        label:'alanmf',
          click:()=>{console.log('shift+G')},
          accelerator:'shift+G'//定义快捷键
      }
    ]
  }
]

const menu = Menu.buildFromTemplate(template)//一般来说, template是一个options类型的数组,用于构建MenuItem。 使用方法可参考前文。还可以将其他字段附加到template,它们将成为菜单项的属性。
Menu.setApplicationMenu(menu)//在macOS上将 menu设置成应用内菜单 在windows和Linux上,menu 将会被设置成窗口顶部菜单在Windows和Linux中

[Menu菜单文档]: “https://www.electronjs.org/zh/docs/latest/api/menu
[role的属性值]: “https://www.electronjs.org/zh/docs/latest/api/menu-item#角色

5.系统托盘(Tray)

添加图标和上下文菜单到系统通知区

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

let tray = null
app.whenReady().then(() => {
  tray = new Tray('/path/to/my/icon') //定义icon的路径
  const contextMenu = Menu.buildFromTemplate([
    { label: 'Item1', type: 'radio' },
    { label: 'Item2', type: 'radio' },
    { label: 'Item3', type: 'radio', checked: true },
    { label: 'Item4', type: 'radio' }
  ])
  tray.setToolTip('This is my application.')//设置鼠标指针在托盘图标上悬停时显示的文本
  tray.setContextMenu(contextMenu)//设置上下文菜单到托盘
})

其实这个Tray跟Menu是布局差不太多的,所以学习起来也不是很难理解了。具体事件和方法也不是特别多,我们就直接看官方API文档吧!

[Tray文档]: “https://www.electronjs.org/zh/docs/latest/api/tray

6.触控板(TouchBar)

注意: TouchBar API目前为实验性质,可能会更改或删除。

如果官网推荐的TouchBar模拟器下载失败,自己搜索一下即可。(如果下载的打不开,那就在应用程序->右键显示包内容->如下)执行就可以了

//touchbar.js
const { app, BrowserWindow, TouchBar } = require('electron')

const { TouchBarLabel, TouchBarButton, TouchBarSpacer } = TouchBar

let spinning = false

// 类似老虎机的滚轴标签
const reel1 = new TouchBarLabel()
const reel2 = new TouchBarLabel()
const reel3 = new TouchBarLabel()

// 旋转结果标签
const result = new TouchBarLabel()

// 旋转按钮
const spin = new TouchBarButton({
  label: '🎰 Spin',
  backgroundColor: '#7851A9',
  click: () => {
    // Ignore clicks if already spinning
    if (spinning) {
      return
    }

    spinning = true
    result.label = ''

    let timeout = 10
    const spinLength = 4 * 1000 // 4 seconds
    const startTime = Date.now()

    const spinReels = () => {
      updateReels()

      if ((Date.now() - startTime) >= spinLength) {
        finishSpin()
      } else {
        // Slow down a bit on each spin
        timeout *= 1.1
        setTimeout(spinReels, timeout)
      }
    }

    spinReels()
  }
})

const getRandomValue = () => {
  const values = ['🍒', '💎', '7️⃣', '🍊', '🔔', '⭐', '🍇', '🍀']
  return values[Math.floor(Math.random() * values.length)]
}

const updateReels = () => {
  reel1.label = getRandomValue()
  reel2.label = getRandomValue()
  reel3.label = getRandomValue()
}

const finishSpin = () => {
  const uniqueValues = new Set([reel1.label, reel2.label, reel3.label]).size
  if (uniqueValues === 1) {
    // All 3 values are the same
    result.label = '💰 Jackpot!'
    result.textColor = '#FDFF00'
  } else if (uniqueValues === 2) {
    // 2个值相同
    result.label = '😍 Winner!'
    result.textColor = '#FDFF00'
  } else {
    // 没有值相同
    result.label = '🙁 Spin Again'
    result.textColor = null
  }
  spinning = false
}

const touchBar = new TouchBar({
  items: [
    spin,
    new TouchBarSpacer({ size: 'large' }),
    reel1,
    new TouchBarSpacer({ size: 'small' }),
    reel2,
    new TouchBarSpacer({ size: 'small' }),
    reel3,
    new TouchBarSpacer({ size: 'large' }),
    result
  ]
})

let window

app.whenReady().then(() => {
  window = new BrowserWindow({
    frame: false,
    titleBarStyle: 'hiddenInset',
    width: 200,
    height: 200,
    backgroundColor: '#000'
  })
  window.loadURL('about:blank')
  window.setTouchBar(touchBar)
})

运行命令:

./node_modules/.bin/electron touchbar.js

[TouchBar文档]: “https://www.electronjs.org/zh/docs/latest/api/touch-bar"

参考链接:

[Electron官方文档]: “https://www.electronjs.org/zh/docs/latest/api/app
[npmjs]: “https://www.npmjs.com/

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2022-2023 alan_mf
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信