预览

开源项目Tokei Kun
一款简洁的周年纪念app,现已发布APK(安卓)和 EXE(Windows)
项目仓库地址:Github Repo
应用下载链接:Github Releases
Preparation for Electron
shell
quasar dev -m electron
# passing extra parameters and/or options to
# underlying "electron" executable:
quasar dev -m electron -- --no-sandbox --disable-setuid-sandbox
# when on Windows and using Powershell:
quasar dev -m electron '--' --no-sandbox --disable-setuid-sandbox
基本命令
bash
quasar dev -m electron
指定以 Electron 模式运行启动 Quasar 开发服务器
传递参数
Linux/MacOS 语法:
bash
quasar dev -m electron -- --no-sandbox --disable-setuid-sandbox
--
: 这个符号表示后面的参数是传递给底层 Electron 可执行文件的,而不是 Quasar CLI
Windows PowerShell 语法:
bash
quasar dev -m electron '--' --no-sandbox --disable-setuid-sandbox
- 在 PowerShell 中需要用引号包裹
--
参数解释
--no-sandbox
禁用 Chromium 的沙盒(sandbox)安全机制沙盒是一种安全功能,限制应用程序对系统资源的访问禁用沙盒可能会降低安全性,但在某些环境下是必要的
--disable-setuid-sandbox
禁用 setuid 沙盒setuid 是一种 Unix 权限机制,允许程序以更高权限运行,在某些 Linux 系统上,如果无法使用 setuid 沙盒,需要禁用此功能
Frameless Electron Window
安装依赖
shell
npm install --save @electron/remote
修改electron-main.js
js
import { app, BrowserWindow, nativeTheme } from 'electron'
import { initialize, enable } from '@electron/remote/main' // <-- add this
import path from 'path'
initialize() // <-- add this
// ...
mainWindow = new BrowserWindow({
width: 1000,
height: 600,
useContentSize: true,
frame: false // <-- add this
webPreferences: {
sandbox: false // <-- to be able to import @electron/remote in preload script
// ...
}
})
enable(mainWindow.webContents) // <-- add this
mainWindow.loadURL(process.env.APP_URL)
// ...
!warning
官方文档中import { initialize, enable } from '@electron/remote/main'
这里我出现了报错
改为import { initialize, enable } from '@electron/remote/main/index.js'正常运行
![[import error.png]]
quasar issue:Electron dev app @electron/remote error · Issue #17971 · quasarframework/quasar
!success\] 成功 接下里我们需要处理窗口拖拽以及最小化、最大化与关闭应用
预加载脚本
由于我们无法直接从渲染线程访问 Electron,需要通过 electron 预加载脚本( src-electron/main-process/electron-preload.js
)提供必要功能。因此我们将其修改为:
js
//src-electron/main-process/electron-preload
import { contextBridge } from 'electron'
import { BrowserWindow } from '@electron/remote'
contextBridge.exposeInMainWorld('myWindowAPI', {
minimize () {
BrowserWindow.getFocusedWindow().minimize()
},
toggleMaximize () {
const win = BrowserWindow.getFocusedWindow()
if (win.isMaximized()) {
win.unmaximize()
} else {
win.maximize()
}
},
close () {
BrowserWindow.getFocusedWindow().close()
}
})
处理窗口拖拽
当我们使用无边框窗口(仅限无边框!)时,还需要为用户提供在屏幕上移动应用窗口的方式。为此,您可以使用 q-electron-drag
和 q-electron-drag--exception
Quasar CSS 辅助类。
!TIPS\] 提示 也许你可以在layout文件中为某些组件添加类`q-electron-drag`试试
该功能允许用户在屏幕上点击、按住并同时拖动鼠标时,拖拽应用程序窗口。
最小化、最大化与关闭应用
在某些vue文件(例如添加在MainLayout.vue中)
Template
vue
<q-space />
<q-btn dense flat icon="minimize" @click="minimize" />
<q-btn dense flat icon="crop_square" @click="toggleMaximize" />
<q-btn dense flat icon="close" @click="closeApp" />
!TIP
若觉得icon
minimize
不太习惯(位于底部),可以使用remove
(竖直居中)
q-space
的作用是将q-btn
挤到右边
选项式
vue
<script>
// We guard the Electron API calls with the optional chaining JS operator,
// but this is only needed if we build same app with other Quasar Modes
// as well (SPA/PWA/Cordova/SSR...)
export default {
setup () {
function minimize () {
window.myWindowAPI?.minimize()
}
function toggleMaximize () {
window.myWindowAPI?.toggleMaximize()
}
function closeApp () {
window.myWindowAPI?.close()
}
return { minimize, toggleMaximize, closeApp }
}
}
</script>
组合式
vue
<script setup>
// We guard the Electron API calls with the optional chaining JS operator,
// but this is only needed if we build same app with other Quasar Modes
// as well (SPA/PWA/Cordova/SSR...)
function minimize() {
if (process.env.MODE === 'electron') {
window.myWindowAPI?.minimize()
}
}
function toggleMaximize() {
if (process.env.MODE === 'electron') {
window.myWindowAPI?.toggleMaximize()
}
}
function closeApp() {
if (process.env.MODE === 'electron') {
window.myWindowAPI?.close()
}
}
</script>
Electron的 Unable to load preload script 报错解决方案-CSDN博客
Build
shell
quasar build -m electron -d
附完整代码
electron-main.js
js
import { app, BrowserWindow, ipcMain } from 'electron'
import { initialize, enable } from '@electron/remote/main/index.js' // <-- add this
import path from 'node:path'
import os from 'node:os'
import { fileURLToPath } from 'node:url'
initialize() // <-- add this
// needed in case process is undefined under Linux
const platform = process.platform || os.platform()
const currentDir = fileURLToPath(new URL('.', import.meta.url))
let mainWindow
async function createWindow () {
/**
* Initial window options
*/
mainWindow = new BrowserWindow({
icon: path.resolve(currentDir, 'icons/icon.png'), // tray icon
width: 1200,
height: 900,
useContentSize: true,
frame: false,
webPreferences: {
sandbox: false, // 开启沙盒则preload脚本被禁用,所以得设为false
contextIsolation: true,
// More info: https://v2.quasar.dev/quasar-cli-vite/developing-electron-apps/electron-preload-script
preload: path.resolve(
currentDir,
path.join(process.env.QUASAR_ELECTRON_PRELOAD_FOLDER, 'electron-preload' + process.env.QUASAR_ELECTRON_PRELOAD_EXTENSION)
)
}
})
enable(mainWindow.webContents) // <-- add this
if (process.env.DEV) {
await mainWindow.loadURL(process.env.APP_URL)
} else {
await mainWindow.loadFile('index.html')
}
if (process.env.DEBUGGING) {
// if on DEV or Production with debug enabled
mainWindow.webContents.openDevTools()
} else {
// we're on production; no access to devtools pls
mainWindow.webContents.on('devtools-opened', () => {
mainWindow.webContents.closeDevTools()
})
}
mainWindow.on('closed', () => {
mainWindow = null
})
}
app.whenReady().then(createWindow)
app.on('window-all-closed', () => {
if (platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (mainWindow === null) {
createWindow()
}
})
electron-preload.js
js
import { contextBridge } from 'electron'
import { BrowserWindow } from '@electron/remote/'
contextBridge.exposeInMainWorld('myWindowAPI', {
minimize () {
BrowserWindow.getFocusedWindow().minimize()
},
toggleMaximize () {
const win = BrowserWindow.getFocusedWindow()
if (win.isMaximized()) {
win.unmaximize()
} else {
win.maximize()
}
},
close () {
BrowserWindow.getFocusedWindow().close()
}
})
/**
* This file is used specifically for security reasons.
* Here you can access Nodejs stuff and inject functionality into
* the renderer thread (accessible there through the "window" object)
*
* WARNING!
* If you import anything from node_modules, then make sure that the package is specified
* in package.json > dependencies and NOT in devDependencies
*
* Example (injects window.myAPI.doAThing() into renderer thread):
*
* import { contextBridge } from 'electron'
*
* contextBridge.exposeInMainWorld('myAPI', {
* doAThing: () => {}
* })
*
* WARNING!
* If accessing Node functionality (like importing @electron/remote) then in your
* electron-main.js you will need to set the following when you instantiate BrowserWindow:
*
* mainWindow = new BrowserWindow({
* // ...
* webPreferences: {
* // ...
* sandbox: false // <-- to be able to import @electron/remote in preload script
* }
* }
*/