安装:

  1. 新建项目文件夹 npm init vite
  2. 安装 electron :npm i -D electron
  3. 安装自动更新:npm i -D electron-squirrel-startup
  4. 安装sass npm i -D sass
  5. 安装插件:npm i -D vite-plugin-electron
    1. <!DOCTYPE html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8" />
    5. <link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    7. <meta http-equiv="Content-Security-Policy" content="script-src 'self'">
    8. <meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
    9. <title>Vite App</title>
    10. </head>
    11. <body>
    12. <div id="root"></div>
    13. <script type="module" src="/src/main.jsx"></script>
    14. </body>
    15. </html>
    ```javascript const { app, BrowserWindow, ipcMain, Tray, nativeImage, Menu } = require(‘electron’) const path = require(‘path’)

if (require(‘electron-squirrel-startup’)) { app.quit() }

let mainWindow, tray

// 主窗口设置 const createWindow = () => { mainWindow = new BrowserWindow({ width: 700, height: 600, frame: false, useContentSize: true, autoHideMenuBar: true, webPreferences: { preload: path.join(dirname, ‘preload.js’), nodeIntegration: true, contextIsolation: false } }) if (app.isPackaged) { mainWindow.loadFile(path.join(dirname, ‘build’, ‘index.html’)) } else { mainWindow.loadURL(‘http://localhost:3000‘) mainWindow.webContents.openDevTools() } } // 初始化 -主窗口 app.whenReady().then(() => { createWindow() // 托盘图标 const icon = nativeImage.createFromPath(path.join(__dirname, ‘icon.png’)) // 托盘 tray = new Tray(icon) // 移动到托盘上的提示 tray.setToolTip(‘electron+react’) // 监听托盘右键事件 tray.on(‘right-click’, () => { // 右键菜单模板 const tempate = [ { label: ‘打开应用’, click: () => mainWindow.restore() }, { label: ‘退出应用’, click: () => app.quit() } ] // 创建托盘右键菜单 const menuConfig = Menu.buildFromTemplate(tempate) // 托盘右键的菜单替代原来的 tray.popUpContextMenu(menuConfig) }) // 监听点击托盘的事件 tray.on(‘click’, () => { // 这里来控制窗口的显示和隐藏 if (mainWindow.isMinimized()) { mainWindow.restore() } else { mainWindow.minimize() } })

app.on(‘activate’, () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow() } }) }) // 关闭 - 主窗口 app.on(‘window-all-closed’, () => { if (process.platform !== ‘darwin’) { app.quit() } })

// 刷新 ipcMain.on(‘reloadApp’, () => { mainWindow.webContents.reload() }) // 最小化 ipcMain.on(‘hideApp’, () => { mainWindow.minimize() }) // 全屏 ipcMain.on(‘fullscreen’, (event) => { if (mainWindow.isMaximized()) { mainWindow.unmaximize() } else { mainWindow.maximize() } event.returnValue = mainWindow.isMaximized() }) // 关闭 ipcMain.on(‘closeApp’, () => { mainWindow = null mainWindow.close() }) const { app, BrowserWindow, ipcMain } = require(‘electron’) const path = require(‘path’)

if (require(‘electron-squirrel-startup’)) { app.quit() }

let mainWindow = null let newWin = null

const createWindow = () => { mainWindow = new BrowserWindow({ width: 1210, height: 800, frame: false, useContentSize: true, webPreferences: { preload: path.join(dirname, ‘preload.js’), nodeIntegration: true, contextIsolation: false } }) if (app.isPackaged) { mainWindow.loadFile(path.join(dirname, ‘build’, ‘index.html’)) } else { mainWindow.loadURL(‘http://localhost:3000‘) mainWindow.webContents.openDevTools() } }

app.whenReady().then(() => { createWindow() app.on(‘activate’, () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow() } }) }) app.on(‘window-all-closed’, () => { if (process.platform !== ‘darwin’) { app.quit() } }) ipcMain.on(‘applyStart’, () => { newWin = new BrowserWindow({ width: 375, height: 872, frame: false, useContentSize: true, webPreferences: { preload: path.join(__dirname, ‘../electron-preload/index.js’), nodeIntegration: true, contextIsolation: false } })

if (app.isPackaged) { mainWindow.loadFile(path.join(__dirname, ‘build’, ‘index.html/apply-start’)) } else { mainWindow.loadURL(‘http://localhost:3000/apply-start‘) mainWindow.webContents.openDevTools() }

newWin.on(‘close’, () => { newWin = null }) }) ipcMain.on(‘closeApplyStart’, () => { newWin.close() newWin = null }) ipcMain.on(‘closeApp’, () => { mainWindow.close() mainWindow = null })

  1. ```javascript
  2. window.addEventListener('DOMContentLoaded', () => {
  3. const replaceText = (selector, text) => {
  4. const element = document.getElementById(selector)
  5. if (element) element.innerText = text
  6. }
  7. for (const type of ['chrome', 'node', 'electron']) {
  8. replaceText(`${type}-version`, process.versions[type])
  9. }
  10. })
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

import compressionPlugin from 'vite-plugin-compression'
import PkgConfig from 'vite-plugin-package-config'
import OptimizationPersist from 'vite-plugin-optimize-persist'

export default defineConfig({
  build: {
    outDir: 'app/build',
    emptyOutDir: false,
    chunkSizeWarningLimit: 10240,
    brotliSize: false,
    assetsDir: 'assets',
    rollupOptions: {
      output: {
        chunkFileNames: 'assets/chunk/[name]-[hash].js',
        entryFileNames: 'assets/chunk/[name]-[hash].js',
        assetFileNames: 'assets/[ext]/[name]-[hash].[ext]'
      }
    }
  },
  plugins: [
    react(),
    PkgConfig(),
    OptimizationPersist(),
    compressionPlugin({ threshold: 10240 })
  ]
})

打包

  1. 安装 Electron Forge:npm i -D @electron-forge/cli
  2. 执行设置 Forge 的脚手架:npx electron-forge import
  3. 打包分发应用程序:npm run make
const router = createRouter({
  history: createWebHashHistory(),
  routes
})
new BrowserWindow({
  useContentSize: true,
  frame: false,
})
<template>
  <div class="app-menu">111</div>
</template>

<script>
export default {
  name: 'app-menu'
}
</script>
<script setup>
import { getCurrentInstance } from 'vue';
const { proxy } = getCurrentInstance()

</script>

<style lang='scss' scoped>
.app-menu {
  width: 100%;
  height: 52px;
  background-color: #fc0;
    // 拖动必须
  -webkit-app-region: drag;
  user-select: none;
}
</style>
packagerConfig: {
    name: 'xxx客户端',
    executableName: 'App',
    extraResource: ['./assets/Readme.txt', './assets/img/a.png'], // 静态文件
    icon: './build/icon' // 不用加后缀,但是需要准备3个文件,win: icon.ico, mac: icon.icns, linux: icon.png,打包时自动识别,linux 在BrowserWindow构造参数中设置
  },

双向通信

使用 ipcMain.handle 监听事件

  ipcMain.handle('showApp', (event, data) => {
    return data
  })

通过预加载脚本暴露 ipcRenderer.invoke

ipcRenderer.invoke('showApp', 'this is show title').then(res => {
  console.log(res)
})

Q&A

打包报错
image.png
上面横线处是出现错误的位置。报错的原因如下:
1、package.json的“author”和“description”在打包时是必填内容,随便填些内容即可打包成功。
2、和项目的绝对路径有关,项目的绝对路径不能出现中文,否则在红线处会报错。

electron禁止鼠标双击放大窗口
在新建窗口时设置

maximizable: false

这样的话双击就不可以最大化了,然后在具体需要最大化的地方再用

 if (mainWindow.isMaximized()) {
    mainWindow.unmaximize()
  } else {
    mainWindow.maximize()
  }