yarn create vite
yarn add electron
yarn add electron-store
yarn add electron-builder
新增main.js、preload.js
javascript
// main.js
const { app, BrowserWindow, ipcMain, globalShortcut } = require('electron')
const path = require('path')
let store // 我们将在稍后动态导入 electron-store
let mainWindow = null
const createWindow = () => {
mainWindow = new BrowserWindow({
width: 1200, // 打开界面宽
minWidth: 1200, // 打开界面最小宽
height: 800, // 打开界面高
minHeight: 800, // 打开界面最小高
fullscreen: false, // 是否启动全屏
resizable: true, // 是否允许调整窗口大小
autoHideMenuBar: true, // 工具栏隐藏
alwaysOnTop: true, // 窗口是否总是显示在其他窗口的上方
icon: path.join(__dirname, './public/favicon.ico'), // 设置窗口图标
webPreferences: {
// 与网页相关的偏好设置
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false
}
})
if (process.env.VITE_DEV_SERVER_URL) {
mainWindow.loadURL(process.env.VITE_DEV_SERVER_URL)
} else {
mainWindow.loadFile(path.join(__dirname, './dist/index.html'))
}
// 注册刷新页面快捷键
globalShortcut.register('Ctrl+R', () => {
mainWindow.reload()
})
// 注册打开控制台快捷键
globalShortcut.register('Ctrl+Shift+I', () => {
mainWindow.webContents.openDevTools()
})
mainWindow.on('closed', () => {
mainWindow = null
// 注销所有快捷键
globalShortcut.unregisterAll()
})
}
app.whenReady().then(async () => {
const Store = (await import('electron-store')).default
store = new Store()
createWindow()
// 在所有窗口关闭时注销快捷键
app.on('window-all-closed', () => {
globalShortcut.unregisterAll()
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
ipcMain.handle('getStoreValue', (event, key) => {
return store.get(key)
})
ipcMain.handle('setStoreValue', (event, key, value) => {
store.set(key, value)
})
ipcMain.handle('delStoreValue', () => {
store.clear()
console.log('已经清理')
})
javascript
// preload.js
const { contextBridge, ipcRenderer } = require('electron')
// 向渲染进程暴露 Electron 特定的 API
contextBridge.exposeInMainWorld('electron', {
getStoreValue: (key) => ipcRenderer.invoke('getStoreValue', key),
setStoreValue: (key, value) =>
ipcRenderer.invoke('setStoreValue', key, value),
delStoreValue: () => ipcRenderer.invoke('delStoreValue')
})
// 添加全局变量来指示是否在 Electron 环境中运行
contextBridge.exposeInMainWorld('isElectron', true)
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const dependency of ['chrome', 'node', 'electron']) {
replaceText(`${dependency}-version`, process.versions[dependency])
}
})
TypeScript
// vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
base: "./", // 必须
});
TypeScript
// app页面添加electron-store测试代码
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue'
// 用于测试electron-store
setTimeout(() => {
console.log('写入', window.electron)
window.electron.setStoreValue('key', '我是写入数据')
}, 1000)
setTimeout(() => {
const v = window.electron.getStoreValue('key')
console.log('读取', v)
}, 5000)
</script>
<template>
<div>
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" class="logo" alt="Vite logo" />
</a>
<a href="https://vuejs.org/" target="_blank">
<img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
</a>
</div>
<HelloWorld msg="Vite + Vue" />
</template>
<style scoped>
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
filter: drop-shadow(0 0 2em #42b883aa);
}
</style>
TypeScript
// src/electron.d.ts
export interface ElectronAPI {
getStoreValue: (key: string) => Promise<any>;
setStoreValue: (key: string, value: any) => Promise<void>;
}
declare global {
interface Window {
electron: ElectronAPI;
}
}
TypeScript
"name": "test",
"private": true,
"version": "0.0.0", // 新增
"description": "hello world",// 新增
"main": "main.js", // 新增
"author": "han", // 新增
"license": "MIT", // 新增
"scripts": {
"dev": "vite",
"build": "vue-tsc -b && vite build",
"start": "electron .", // 新增
"build-builder": "electron-builder", // 新增
"preview": "vite preview"
},
"build": { // 新增build
"appId": "com.yourcompany.yourapp",
"win": {
"target": "nsis",
"icon": "./public/icon.ico"
},
"linux": {
"icon": "./public/icon.png"
},
"dmg": {
"contents": [
{
"x": 410,
"y": 150,
"type": "link",
"path": "/Applications"
},
{
"x": 130,
"y": 150,
"type": "file"
}
]
},
"mac": {
"icon": "./public/icon.ico"
},
"files": [
"dist/**/*",
"main.js",
"preload.js"
],
"directories": {
"output": "awBack2"
},
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"shortcutName": "aw"
}
},
yarn build
yarn start
yarn build-builder
TypeScript
{
"name": "test",
"private": true,
"version": "0.0.0",
"description": "hello world",
"main": "main.js",
"author": "han",
"license": "MIT",
"scripts": {
"dev": "vite",
"build": "vue-tsc -b && vite build",
"start": "electron .",
"build-builder": "electron-builder",
"preview": "vite preview"
},
"build": {
"appId": "com.yourcompany.yourapp",
"win": {
"target": "nsis",
"icon": "./public/icon.ico"
},
"linux": {
"icon": "./public/icon.png"
},
"dmg": {
"contents": [
{
"x": 410,
"y": 150,
"type": "link",
"path": "/Applications"
},
{
"x": 130,
"y": 150,
"type": "file"
}
]
},
"mac": {
"icon": "./public/icon.ico"
},
"files": [
"dist/**/*",
"main.js",
"preload.js"
],
"directories": {
"output": "awBack2"
},
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"shortcutName": "aw"
}
},
"dependencies": {
"electron-store": "^10.0.0",
"vue": "^3.4.37"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.1.2",
"electron": "^32.0.1",
"electron-builder": "^24.13.3",
"typescript": "^5.5.3",
"vite": "^5.4.1",
"vue-tsc": "^2.0.29"
}
}