vue3+ts+vite+electron+electron-store+electron-builder打包可安装包

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"
  }
}

相关推荐
雪碧聊技术5 分钟前
深入解析Vue中v-model的双向绑定实现原理
前端·javascript·vue.js·v-model
快起来别睡了7 分钟前
手写 Ajax 与 Promise:从底层原理到实际应用
前端
打不着的大喇叭1 小时前
uniapp的光标跟随和打字机效果
前端·javascript·uni-app
无我Code1 小时前
2025----前端个人年中总结
前端·年终总结·创业
程序猿阿伟1 小时前
《前端路由重构:解锁多语言交互的底层逻辑》
前端·重构
Sun_light1 小时前
6个你必须掌握的「React Hooks」实用技巧✨
前端·javascript·react.js
爱学习的茄子1 小时前
深度解析JavaScript中的call方法实现:从原理到手写实现的完整指南
前端·javascript·面试
莫空00001 小时前
Vue组件通信方式详解
前端·面试
呆呆的心1 小时前
揭秘 CSS 伪元素:不用加标签也能玩转出花的界面技巧 ✨
前端·css·html
百锦再1 小时前
重新学习Vue中的按键监听和鼠标监听
javascript·vue.js·vue·计算机外设·click·up·down