乐趣区

关于前端:从零开始的electron开发菜单与快捷键

菜单与快捷键

尽管咱们在平时应用桌面软件时,大多数状况下都是用鼠标进行操作,一些软件提供了菜单与键盘快捷键进行操作,mac 零碎上比拟常见一些。如果在应用软件时有对应的快捷键操作或者菜单,会让用户的应用体验更加顺畅和不便一点。本章次要对注册快捷键的几种形式进行阐明以及菜单的零碎差异化解决。

Menu 菜单

菜单这个货色呢,个别常见于 mac 零碎上,win 的话国内比拟少见,算是一种约定俗成吧。实际上快捷键和菜单方面能够说是一体的,咱们能够在菜单上注册对应的键盘按键,故 mac 零碎能够应用这个形式把快捷键一起解决了。
长处:最简洁的快捷键解决,简略不便。
毛病:只能在应用程序被聚焦时触发(焦点在程序上,不只是显示),因为 win 个别不应用菜单,故只能用于 mac 上。

import {app, dialog, Menu} from 'electron'
import config from './index'
import global from './global'
const os = require('os')
const isMac = process.platform === 'darwin'

const menuConfig = [{
  label: app.name,
  submenu: [{
    label: '对于',
    accelerator: isMac ? 'Alt+Cmd+I' : 'Alt+Shift+I',
    click: function () {info()
    }
  }]
}, {
  label: '设置',
  submenu: [{
    label: '疾速重启',
    accelerator: 'CmdOrCtrl+F5',
    role: 'reload'
  }, {
    label: '退出',
    accelerator: 'CmdOrCtrl+Q',
    role: 'quit'
  }]
}, {
  label: '开发者设置',
  submenu: [{
    label: '切换到开发者模式',
    accelerator: 'CmdOrCtrl+I',
    role: 'toggledevtools'
  }]
}]

function info() {
  dialog.showMessageBox({
    title: '对于',
    type: 'info',
    message: 'vue-cli-electron',
    // detail: ` 版本信息:\nelectron 版本:${process.versions.electron}\n 以后零碎:${os.type()} ${os.arch()} ${os.release()}\n 以后版本:${process.env.VUE_APP_ENV},${process.env.VUE_APP_VERSION}`,
    detail: ` 版本信息:\nelectron 版本:${process.versions.electron}\n 以后零碎:${os.type()} ${os.arch()} ${os.release()}\n 以后版本:${global.envConfig.VUE_APP_ENV},${global.envConfig.VUE_APP_VERSION}`,
    noLink: true,
    buttons: ['确定']
  })
}

菜单的快捷键注册是用 accelerator 增加的,当然你也能够依据零碎的不同进行差异化解决,role的话是 electron 内置的行为,比方 copy - 复制paste - 粘贴 等等,能够参考官网文档

在 windows 下咱们把菜单暗藏掉,mac 的话失常显示:

function setMenu(win) {
  let menu
  if (config.devToolsShow) {menu = Menu.buildFromTemplate(menuConfig)
    Menu.setApplicationMenu(menu)
    win.webContents.openDevTools({mode: 'detach'})
  } else {if (isMac) {menu = Menu.buildFromTemplate(menuConfig)
      Menu.setApplicationMenu(menu)
    } else {Menu.setApplicationMenu(null)
    }
    win.webContents.openDevTools({mode: 'detach'})
    // win.webContents.closeDevTools()}
}

主过程监听快捷键

globalShortcut

globalShortcut模块能够在操作系统中注册 / 登记全局快捷键,然而集体不举荐用这种形式来注册快捷键:
长处:响应级别最高,只有软件在运行中,无论软件处于什么状态(没聚焦甚至暗藏),都会响应。
毛病:如果快捷键曾经被其余应用程序注册掉,那么会注册失败。注册胜利后,因为其响应级别最高,所以会影响其他软件快捷键的应用,在启动软件后,其他软件的快捷键雷同的话其他软件的快捷键无奈失效。

// 主过程,渲染过程能够应用 remote 来注册:const {app, globalShortcut} = require('electron')

app.whenReady().then(() => {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()})

electron-localshortcut

第三方的 npm 包,api 和 globalShortcut 基本一致,相对而言没那么激进,是针对于窗口注册的,故需传入窗口进行注册,当窗口没聚焦时,不会相应。
长处:针对于窗口的监听,响应需处于聚焦状态,基本上能满足大多数场景。
毛病:须要引入第三方包,页面有 webview,且焦点在 webview 上时无奈触发。

npm install --save electron-localshortcut

const electronLocalshortcut = require('electron-localshortcut')
const win = new BrowserWindow()
win.loadUrl('https://github.com')
win.show()

electronLocalshortcut.register(win, 'Ctrl+A', () => {console.log('You pressed ctrl & A')
})
// 查看快捷键是否注册胜利
console.log(electronLocalshortcut.isRegistered(win, 'Ctrl+A'))
// 登记快捷键
electronLocalshortcut.unregister(win, 'Ctrl+A')
electronLocalshortcut.unregisterAll(win)

渲染过程监听快捷键

本人页面监听

实际上就是网页 keyup 的监听,能够用通信把键盘按键的信息传送到主过程。
当然你也能够在主过程中应用 before-input-event,渲染过程中调度页面中的 keydown 和 keyup 事件之前,会收回 before-input-event 事件,能够在主过程捕捉按键信息。
长处:针对于页面的监听,罕用于某个页面的非凡按键监听。
毛病:页面有 iframe 或 webview,且焦点在 iframe 或 webview 上时,无奈触发(iframe 能够触发 before-input-event)。

渲染过程:window.addEventListener('keyup', handleKeyPress, true)
function handleKeyPress(event) {$message.success(`keyup 监听 ${event.key}`)
  console.log(`You pressed ${event.key}`)
}
window.removeEventListener('keyup', handleKeyPress, true)


主过程:win.webContents.on('before-input-event', (event, input) => {if (input.control && input.key.toLowerCase() === 'i') {console.log('Pressed Control+I')
    event.preventDefault()}
})

组合按键:当然一般来说快捷键都是组合按键的,咱们能够借助第三方按键库来解决。

npm i mousetrap

渲染过程:Mousetrap.bind('ctrl+k', function() {$message.success(`Mousetrap ctrl+k`)
})

Mousetrap.unbind('ctrl+k')

webview 或 iframe 嵌入网页监听

如果咱们的页面中有 webview 或 iframe,且焦点在 webview 或 iframe 上时,会导致咱们的快捷键生效。

  1. Menu 菜单和 globalShortcut 不会生效。
  2. electron-localshortcut:webview 有效,iframe 无效
  3. keyup:webview 有效,iframe 有效,before-input-event:iframe 无效。

这样看下来在利用 webview 的时候比拟难解决,只有 Menu 菜单和 globalShortcut 对其失效,那么还有其余形式吗?
咱们能够通过向 webview 注入 preload.js 来进行键盘按键的监听,而后将键盘信息回传给咱们的渲染过程

vue.config.js 中 electronBuilder 批改为:preload: {preload: 'src/renderer/preload/ipcRenderer.js', webviewPreload: 'src/renderer/preload/webview.js'}

webviewPreload 是咱们向 webview 注入的 js,当然你得新建对应文件,留神一下咱们建设的文件是 webview.js,编译后为 webviewPreload.js,故咱们注入的为 webviewPreload.js。注:webview 启动及 Node integration 启用须在主过程窗口 webPreferences 进行配置。webview.js:const {ipcRenderer} = require('electron')
window.addEventListener('keyup', handleKeyPress, true)
function handleKeyPress(event) {console.log(event.key)
    ipcRenderer.sendToHost('ipc-message', {data: event.key})
}

渲染过程:<webview ref="webviewRef" class="webview" src="https://www.baidu.com" :preload="state.preload" ></webview>
const {remote} = require('electron')
const path = require('path')

const webview = webviewRef.value
state.preload = path.resolve(remote.app.getAppPath(), './webviewPreload.js')
webview.addEventListener('ipc-message', webMessage)
webview.addEventListener('dom-ready', () => {webview.openDevTools()
})
function webMessage(event) {console.log('在此监听事件中接管 webview 嵌套页面所响应的事件', event)
  $message.success(`webview:${event.args[0].data}`)
}

简略梳理一下,咱们把 webviewPreload.js 注入 webview,通过这个 js 进行键盘的 keyup 监听,而后通过 sendToHost 把信息回传给渲染过程,渲染过程中获取回传的信息。
渲染过程是看不到咱们注入 js 以及 webview 的打印,能够应用 webview.openDevTools(),关上 webview 的控制台查看。
本例子就没阐明组合键了,想用组合键请自行注入 mousetrap 进行操作。

本系列更新只有利用周末和下班时间整顿,比拟多的内容的话更新会比较慢,心愿能对你有所帮忙,请多多 star 或点赞珍藏反对一下

本文地址:链接
本文 github 地址:链接

退出移动版