預覽
開源項目Tokei Kun
一款簡潔的周年紀念app,現已發布APK(安卓)和 EXE(Windows)
項目倉庫地址:Github Repo
應用下載鏈接:Github Releases
Preparation for Electron
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
基本命令
quasar dev -m electron
指定以 Electron 模式運行啟動 Quasar 開發服務器
傳遞參數
Linux/MacOS 語法:
quasar dev -m electron -- --no-sandbox --disable-setuid-sandbox
--
: 這個符號表示后面的參數是傳遞給底層 Electron 可執行文件的,而不是 Quasar CLI
Windows PowerShell 語法:
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
安裝依賴
npm install --save @electron/remote
修改electron-main.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 thiswebPreferences: {sandbox: false // <-- to be able to import @electron/remote in preload script// ...}
})enable(mainWindow.webContents) // <-- add thismainWindow.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
)提供必要功能。因此我們將其修改為:
//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
<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]
若覺得iconminimize
不太習慣(位于底部),可以使用remove
(豎直居中)
q-space
的作用是將q-btn
擠到右邊
選項式
<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>
組合式
<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
quasar build -m electron -d
附完整代碼
electron-main.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 mainWindowasync function createWindow () {/*** Initial window options*/mainWindow = new BrowserWindow({icon: path.resolve(currentDir, 'icons/icon.png'), // tray iconwidth: 1200,height: 900,useContentSize: true,frame: false,webPreferences: {sandbox: false, // 開啟沙盒則preload腳本被禁用,所以得設為falsecontextIsolation: true,// More info: https://v2.quasar.dev/quasar-cli-vite/developing-electron-apps/electron-preload-scriptpreload: path.resolve(currentDir,path.join(process.env.QUASAR_ELECTRON_PRELOAD_FOLDER, 'electron-preload' + process.env.QUASAR_ELECTRON_PRELOAD_EXTENSION))}})enable(mainWindow.webContents) // <-- add thisif (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 enabledmainWindow.webContents.openDevTools()} else {// we're on production; no access to devtools plsmainWindow.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
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* }* }*/