# 业务项目整合
# 初步整合
导入前端Vue3的项目到Rnederer文件夹下;
修改
tsconfig.json
文件{ "extends": "../../tsconfig.json", "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./src/*"] }, "lib": ["ESNext", "dom", "dom.iterable"], "jsx": "preserve", "resolveJsonModule": true, "allowJs": true, "noImplicitAny": false }, "include": [ "src/**/*.vue", "src/**/*.ts", "src/**/*.tsx", "types/**/*.d.ts", "../../types/**/*.d.ts", "../preload/types/electron-api.d.ts" ] }
导入资源文件夹
public
,配置index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="Content-Security-Policy" content="script-src 'self' blob:" /> <meta content="width=device-width, initial-scale=1.0" name="viewport" /> <title>toimc社区</title> <link rel="stylesheet" href="./public/layui/layui.css" /> </head> <body> <div id="app"></div> <script src="./src/index.ts" type="module"></script> </body> </html>
更新项目依赖
package.json
"devDependencies": { "@types/axios": "^0.14.0", "@types/electron-devtools-installer": "2.2.0", "@types/i18n": "^0.13.1", "@types/lodash": "^4.14.168", "@types/node": "^14.14.31", "@types/uuid": "^8.3.0", "@types/yup": "^0.29.11", "@typescript-eslint/eslint-plugin": "5.3.0", "@typescript-eslint/parser": "^5.3.0", "@vitejs/plugin-vue": "1.9.4", "cross-env": "7.0.3", "electron": "15.3.0", "electron-builder": "22.13.1", "electron-devtools-installer": "3.2.0", "eslint": "8.1.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-vue": "8.0.3", "lint-staged": "11.2.6", "playwright": "1.16.3", "prettier": "^2.4.1", "sass": "^1.43.4", "simple-git-hooks": "2.7.0", "typescript": "4.4.4", "vite": "2.6.13", "vue-tsc": "0.28.10" }, "dependencies": { "@vee-validate/i18n": "^4.1.20", "@vee-validate/rules": "^4.1.20", "axios": "^0.21.1", "dayjs": "^1.10.4", "electron-updater": "4.6.1", "i18n": "^0.13.3", "qs": "^6.9.6", "uuid": "^8.3.2", "vee-validate": "^4.0.4", "vue": "3.2.21", "vue-router": "4.0.12", "vuex": "^4.0.2", "yup": "^0.32.9" }
修改服务端的端口
renderer/vite.config.js
,这样可以请求到正确的后台API接口:/** * @type {import('vite').UserConfig} * @see https://vitejs.dev/config/ */ const config = { //.. server: { fs: { strict: true }, port: 8000 }, // ... } export default config
# Electron中的菜单
# 顶部菜单
修改main/src/index.ts
文件:
const isSingleInstance = app.requestSingleInstanceLock();
const isMac = process.platform === 'darwin'
const template: MenuItemConstructorOptions[] = [
{ role: 'appMenu' },
// ...(isMac ? [{
// label: app.name,
// submenu: [
// 这里还有一个知识,accelerator是快捷键的设置
// { role: 'about', label: '关于我们', accelerator: 'CmdOrCtrl+1' },
// { type: 'separator' },
// { role: 'services' },
// { type: 'separator' },
// { role: 'hide' },
// { role: 'hideOthers' },
// { role: 'unhide' },
// { type: 'separator' },
// { role: 'quit' }
// ]
// }] as MenuItemConstructorOptions[] : []),
{ role: 'fileMenu' },
{ role: 'editMenu' },
{ role: 'viewMenu' },
{ role: 'windowMenu' },
{
role: 'help',
submenu: [
{
label: '查看帮助',
click: async () => {
await shell.openExternal('https://front-end.toimc.com')
}
}
]
}
]
// 设置electron应用的菜单
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
注意:
- role是内置的一些默认的菜单项;
- submenu是自定义的菜单项;
type: 'separator'
是一个分隔符;
# Docker菜单
说明:Docker菜单适合于macOS!
修改main/src/index.ts
文件:
// 平台判断
const isMac = process.platform === 'darwin'
const dockerMenu: MenuItemConstructorOptions[] = [{
label: 'Docker',
submenu: [
{
label: 'sub1',
click: () => {
console.log('from sub1')
}
},
{
label: 'sub2'
},
]
}]
const dockMenu = Menu.buildFromTemplate(dockerMenu)
// Install "Vue.js devtools"
if (import.meta.env.MODE === 'development') {
app.whenReady()
.then(() => import('electron-devtools-installer'))
.then(({default: installExtension, VUEJS3_DEVTOOLS}) => installExtension(VUEJS3_DEVTOOLS, {
loadExtensionOptions: {
allowFileAccess: true,
},
}))
.then(() => {
if (isMac) {
// 加入dock菜单
app.dock.setMenu(dockMenu)
}
})
.catch(e => console.error('Failed install extension:', e));
}
# 右键菜单(原生)
需要使用到ipc的通信:
为了保证安全,在preload/src/index.ts
中注册Ipc事件:
import type { IpcRendererEvent} from 'electron';
import {contextBridge, ipcRenderer} from 'electron';
const _ipcRenderer = {
// 暴露出去的ipcRenderer上的API
on: (channel: string, listener: (event: IpcRendererEvent, ...args: any[]) => void)=> {
ipcRenderer.on(channel, listener);
return _ipcRenderer
},
send: (channel: string, ...args: any[]) => {
ipcRenderer.send(channel, ...args);
}
}
const apiKey = 'electron';
/**
* @see https://github.com/electron/electron/issues/21437#issuecomment-573522360
*/
const api: ElectronApi = {
versions: process.versions,
ipcRenderer: _ipcRenderer
};
/**
* The "Main World" is the JavaScript context that your main renderer code runs in.
* By default, the page you load in your renderer executes code in this world.
*
* @see https://www.electronjs.org/docs/api/context-bridge
*/
contextBridge.exposeInMainWorld(apiKey, api);
// window.electron.versions
在主进程中进行注册,文件main/src/index.ts
ipcMain.on('show-context-menu', (event) => {
console.log('🚀 ~ file: index.ts ~ line 172 ~ ipcMain.on ~ event', event)
const win = BrowserWindow.fromWebContents(event.sender)
if (win) {
const clickMenu: MenuItemConstructorOptions[] = [{
label: 'Docker',
submenu: [
{
label: 'sub1',
click: () => {
event.sender.send('click-pop-menu', {
'event': 'sub1-clicked',
'data': 'hello'
})
}
},
{
label: 'sub2'
},
]
}]
const popMenu = Menu.buildFromTemplate(clickMenu)
popMenu.popup({window: win});
}
})
渲染进程中:
// preload会加载,添加到window[apiKey]
const {
ipcRenderer: { send, on }
} = window.electron
window.addEventListener('contextmenu', (e) => {
e.preventDefault()
// 2.ipcRenderer send -> menu请求
send('show-context-menu')
})
效果:
# 快捷键
快捷键可以包含多个功能键和一个键码的字符串,由符号+
结合,用来定义你应用中的键盘快捷键
示例
CommandOrControl+A
CommandOrControl+Shift+Z
快捷方式使用 register
(opens new window) 方法在 globalShortcut
(opens new window) 模块中注册, 即:
const { app, globalShortcut } = require('electron')
app.whenReady().then(() => {
// 注册一个 'v' 快捷键监听器.
// 全屏控制
globalShortcut.register('CmdOrCtrl+1', () => {
const win = BrowserWindow.getFocusedWindow()
win?.setFullScreen(!win?.isFullScreen())
// 还可以尝试 app.showAboutPannel() 这个就是关于我们
})
})
通过:
- 菜单来查看设置是否成功:
- 还可以通过API:
globalShortcut.isRegistered(accelerator)
来判断注册是否成功;
# 跨平台提醒
在 Linux 和 Windows 上, Command
键没有任何效果, 所以使用 CommandOrControl
表述, macOS 是 Command
,在 Linux 和 Windows 上是Control
。
使用 Alt
按键替代 Option
按键。 使用 Alt 键代替Option. Option
键只在 macOS 系统上存在, 而 Alt
键在任何系统上都有效。
Super
(或 Meta
) 键对应Windows 和 Linux 系统上的 Windows
键,但在 macOS 里为 Cmd
键。
# 可用的功能键
Command
(缩写为Cmd
)Control
(缩写为Ctrl
)CommandOrControl
(缩写为CmdOrCtrl
)Alt
Option
AltGr
Shift
Super
元数据
# 可用的普通按键
0
到9
A
到Z
F1
到F24
- 类似
~
,!
,@
,#
,$
的标点符号 Plus
Space
Tab
大写锁定(Capslock)
数字锁定(Numlock)
滚动锁定
Backspace
删除
Insert
Return
(等同于Enter
)Up
,Down
,Left
andRight
Home
和End
PageUp
和PageDown
Escape
(缩写为Esc
)VolumeUp
,VolumeDown
和VolumeMute
MediaNextTrack
、MediaPreviousTrack
、MediaStop
和MediaPlayPause
PrintScreen
- 小键盘按键
num1
-num9
-数字1-数字9numdec
- 小数点numadd
- 加号numsub
- 减号nummult
- 乘号numdiv
- 除号
# 国际化
Electron默认的菜单是英文的,很多时候国内的应用场景都需要有中文的菜单,这个时候就需要国际化了。常用的方案就是i18n
,见官网 (opens new window)。
步骤如下:
- 安装依赖:
npm i -S i18n
- 创建对应的
locales
目录:
- 添加对应的译文
json
文件:
{
"paste": "粘贴"
}
- 修改
main/index.ts
:
import i18n from 'i18n'
// 国际化
i18n.configure({
locales: ['zh-CN'],
directory: join(__dirname, '../locales'),
})
app.whenReady()
.then(() => {
createWindow()
// 国际化
// 方法一:
// const locale = app.getLocale()
// i18n.setLocale(locale)
// 方法二:
i18n.setLocale('en') // 这里的设置要与自己的json文件名对应
console.log(i18n.__('paste'))
// ...
}
← 与主流的框架集成 第三方登录(扫码登录) →