quasar electron mode如何打包无边框桌面应用程序

预览

开源项目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-dragq-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

若觉得iconminimize不太习惯(位于底部),可以使用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
 *   }
 * }
 */
相关推荐
Electrolux2 小时前
【使用教程】一个前端写的自动化rpa工具
前端·javascript·程序员
赵大仁3 小时前
深入理解 Pinia:Vue 状态管理的革新与实践
前端·javascript·vue.js
小小小小宇3 小时前
业务项目中使用自定义Webpack 插件
前端
小小小小宇3 小时前
前端AST 节点类型
前端
小小小小宇4 小时前
业务项目中使用自定义eslint插件
前端
babicu1234 小时前
CSS Day07
java·前端·css
小小小小宇4 小时前
业务项目使用自定义babel插件
前端
前端码虫4 小时前
JS分支和循环
开发语言·前端·javascript
GISer_Jing4 小时前
MonitorSDK_性能监控(从Web Vital性能指标、PerformanceObserver API和具体代码实现)
开发语言·前端·javascript
余厌厌厌4 小时前
墨香阁小说阅读前端项目
前端