Vue集成 #
一、项目搭建 #
1.1 使用 Vite 创建项目 #
bash
# 创建 Vue + TypeScript 项目
npm create vite@latest my-electron-vue -- --template vue-ts
# 进入项目目录
cd my-electron-vue
# 安装 Electron
npm install electron --save-dev
npm install electron-builder --save-dev
# 安装开发工具
npm install vite-plugin-electron --save-dev
1.2 项目结构 #
text
my-electron-vue/
├── electron/
│ ├── main.ts # 主进程
│ ├── preload.ts # 预加载脚本
│ └── utils/ # 工具函数
├── src/
│ ├── App.vue # Vue 根组件
│ ├── main.ts # 入口文件
│ ├── components/ # 组件目录
│ ├── composables/ # 组合式函数
│ ├── stores/ # 状态管理
│ ├── views/ # 页面组件
│ └── types/ # 类型定义
├── public/ # 静态资源
├── vite.config.ts # Vite 配置
├── electron-builder.yml # 打包配置
└── package.json
1.3 Vite 配置 #
typescript
// vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import electron from 'vite-plugin-electron';
import path from 'path';
export default defineConfig({
plugins: [
vue(),
electron([
{
entry: 'electron/main.ts',
onstart(options) {
options.startup();
},
vite: {
build: {
outDir: 'dist-electron',
rollupOptions: {
external: ['electron']
}
}
}
},
{
entry: 'electron/preload.ts',
onstart(options) {
options.reload();
},
vite: {
build: {
outDir: 'dist-electron'
}
}
}
])
],
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
},
base: './',
build: {
outDir: 'dist'
}
});
二、主进程配置 #
2.1 主进程入口 #
typescript
// electron/main.ts
import { app, BrowserWindow, ipcMain } from 'electron';
import path from 'path';
const isDev = !app.isPackaged;
let mainWindow: BrowserWindow | null = null;
function createWindow() {
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: false,
contextIsolation: true
}
});
if (isDev) {
mainWindow.loadURL('http://localhost:5173');
mainWindow.webContents.openDevTools();
} else {
mainWindow.loadFile(path.join(__dirname, '../dist/index.html'));
}
mainWindow.on('closed', () => {
mainWindow = null;
});
}
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (mainWindow === null) {
createWindow();
}
});
2.2 预加载脚本 #
typescript
// electron/preload.ts
import { contextBridge, ipcRenderer } from 'electron';
contextBridge.exposeInMainWorld('electronAPI', {
getAppInfo: () => ipcRenderer.invoke('get-app-info'),
openFile: () => ipcRenderer.invoke('open-file'),
saveFile: (content: string) => ipcRenderer.invoke('save-file', content)
});
三、Vue 集成 #
3.1 类型定义 #
typescript
// src/types/electron.d.ts
export interface ElectronAPI {
getAppInfo: () => Promise<{ version: string; platform: string }>;
openFile: () => Promise<string | null>;
saveFile: (content: string) => Promise<boolean>;
}
declare global {
interface Window {
electronAPI: ElectronAPI;
}
}
3.2 组合式函数 #
typescript
// src/composables/useElectron.ts
import { ref, onMounted } from 'vue';
export function useAppInfo() {
const info = ref<{ version: string; platform: string } | null>(null);
const loading = ref(true);
onMounted(async () => {
info.value = await window.electronAPI.getAppInfo();
loading.value = false;
});
return { info, loading };
}
export function useFileOperations() {
const openFile = async () => {
return await window.electronAPI.openFile();
};
const saveFile = async (content: string) => {
return await window.electronAPI.saveFile(content);
};
return { openFile, saveFile };
}
3.3 Vue 组件示例 #
vue
<!-- src/App.vue -->
<script setup lang="ts">
import { ref } from 'vue';
import { useAppInfo, useFileOperations } from './composables/useElectron';
const { info, loading } = useAppInfo();
const { openFile, saveFile } = useFileOperations();
const content = ref('');
const handleOpen = async () => {
const fileContent = await openFile();
if (fileContent) {
content.value = fileContent;
}
};
const handleSave = async () => {
await saveFile(content.value);
};
</script>
<template>
<div class="app" v-if="!loading">
<header>
<h1>Electron + Vue App</h1>
<p>Version: {{ info?.version }}</p>
<p>Platform: {{ info?.platform }}</p>
</header>
<main>
<div class="toolbar">
<button @click="handleOpen">Open</button>
<button @click="handleSave">Save</button>
</div>
<textarea
v-model="content"
placeholder="Enter text here..."
/>
</main>
</div>
<div v-else>Loading...</div>
</template>
<style scoped>
.app {
padding: 20px;
}
.toolbar {
margin-bottom: 10px;
}
.toolbar button {
margin-right: 10px;
}
textarea {
width: 100%;
height: 300px;
}
</style>
四、状态管理 #
4.1 使用 Pinia #
bash
npm install pinia
typescript
// src/stores/app.ts
import { defineStore } from 'pinia';
export const useAppStore = defineStore('app', {
state: () => ({
theme: 'light' as 'light' | 'dark',
sidebarOpen: true
}),
actions: {
setTheme(theme: 'light' | 'dark') {
this.theme = theme;
},
toggleSidebar() {
this.sidebarOpen = !this.sidebarOpen;
}
}
});
4.2 使用组件 #
vue
<!-- src/components/ThemeToggle.vue -->
<script setup lang="ts">
import { useAppStore } from '../stores/app';
const store = useAppStore();
</script>
<template>
<button @click="store.setTheme(store.theme === 'light' ? 'dark' : 'light')">
Current theme: {{ store.theme }}
</button>
</template>
五、路由配置 #
5.1 安装 Vue Router #
bash
npm install vue-router
5.2 路由配置 #
typescript
// src/router/index.ts
import { createRouter, createWebHashHistory } from 'vue-router';
import Home from '../views/Home.vue';
const routes = [
{ path: '/', name: 'Home', component: Home },
{
path: '/settings',
name: 'Settings',
component: () => import('../views/Settings.vue')
},
{
path: '/about',
name: 'About',
component: () => import('../views/About.vue')
}
];
const router = createRouter({
history: createWebHashHistory(),
routes
});
export default router;
5.3 入口文件 #
typescript
// src/main.ts
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';
import router from './router';
import './style.css';
const app = createApp(App);
app.use(createPinia());
app.use(router);
app.mount('#app');
六、打包配置 #
6.1 package.json #
json
{
"name": "my-electron-vue",
"version": "1.0.0",
"main": "dist-electron/main.js",
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build && electron-builder",
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.3.11",
"vue-router": "^4.2.5",
"pinia": "^2.1.7"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.5.2",
"electron": "^28.0.0",
"electron-builder": "^24.9.1",
"typescript": "^5.3.3",
"vite": "^5.0.8",
"vite-plugin-electron": "^0.28.0",
"vue-tsc": "^1.8.25"
}
}
6.2 electron-builder.yml #
yaml
appId: com.example.myapp
productName: My Electron Vue App
directories:
output: release
files:
- dist/**/*
- dist-electron/**/*
mac:
icon: build/icon.icns
win:
icon: build/icon.ico
linux:
icon: build/icon.png
七、最佳实践 #
7.1 开发建议 #
markdown
- [ ] 使用 TypeScript 类型安全
- [ ] 使用组合式 API
- [ ] 组件化开发
- [ ] Pinia 状态管理
- [ ] IPC 封装为组合式函数
7.2 性能优化 #
vue
<!-- 使用异步组件 -->
<script setup lang="ts">
import { defineAsyncComponent } from 'vue';
const Settings = defineAsyncComponent(() =>
import('./views/Settings.vue')
);
</script>
<template>
<Suspense>
<template #default>
<Settings />
</template>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
</template>
八、总结 #
8.1 核心要点 #
| 要点 | 说明 |
|---|---|
| Vite | 推荐的构建工具 |
| 组合式 API | Vue 3 推荐写法 |
| IPC 封装 | 组合式函数封装 |
| Pinia | 推荐的状态管理 |
8.2 下一步 #
现在你已经掌握了 Vue 集成,接下来让我们学习 TypeScript支持,深入了解 Electron 的 TypeScript 开发!
最后更新:2026-03-28