Vue + Electron 实战项目
本章节我们将使用 Vue + Electron 制作一个笔记应用,这个实战项目名为 VueElectronNotes,功能涵盖多窗口、托盘、文件操作和 IPC 通信,是初学者练手非常合适的项目。
如果你还不了解 Vue,可以先参考:Vue 教程。
一、项目功能
- 桌面笔记应用(Notes)
- 主窗口显示笔记列表
- 新建笔记弹出子窗口
- 系统托盘图标,最小化到托盘
- 文件本地保存/读取
- 渲染进程与主进程安全通信
二、项目初始化
1. 创建 Vue 项目
vue create VueElectronNotes cd VueElectronNotes
选择默认 preset(Babel + ESLint)。
2. 安装 Electron 及依赖
npm install --save-dev electron electron-builder concurrently wait-on npm install electron-store
electron-store
用于本地数据持久化
三、主进程配置
electron-main.js:
实例
const { app, BrowserWindow, Tray, Menu, ipcMain } = require('electron')
const path = require('path')
const Store = require('electron-store')
let mainWindow, noteWindow, tray
const store = new Store()
function createMainWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false
}
})
if (process.env.NODE_ENV === 'development') {
mainWindow.loadURL('http://localhost:8080')
} else {
mainWindow.loadFile('dist/index.html')
}
mainWindow.on('minimize', (e) => {
e.preventDefault()
mainWindow.hide()
})
createTray()
}
function createNoteWindow() {
noteWindow = new BrowserWindow({
width: 400,
height: 300,
parent: mainWindow,
modal: true,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false
}
})
noteWindow.loadFile('note.html')
}
function createTray() {
tray = new Tray(path.join(__dirname, 'assets/icon.png'))
const contextMenu = Menu.buildFromTemplate([
{ label: '显示主窗口', click: () => mainWindow.show() },
{ label: '退出', click: () => app.quit() }
])
tray.setToolTip('VueElectronNotes')
tray.setContextMenu(contextMenu)
}
app.whenReady().then(createMainWindow)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
ipcMain.handle('get-notes', () => {
return store.get('notes', [])
})
ipcMain.on('save-note', (event, note) => {
const notes = store.get('notes', [])
notes.push(note)
store.set('notes', notes)
mainWindow.webContents.send('update-notes', notes)
})
const path = require('path')
const Store = require('electron-store')
let mainWindow, noteWindow, tray
const store = new Store()
function createMainWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false
}
})
if (process.env.NODE_ENV === 'development') {
mainWindow.loadURL('http://localhost:8080')
} else {
mainWindow.loadFile('dist/index.html')
}
mainWindow.on('minimize', (e) => {
e.preventDefault()
mainWindow.hide()
})
createTray()
}
function createNoteWindow() {
noteWindow = new BrowserWindow({
width: 400,
height: 300,
parent: mainWindow,
modal: true,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false
}
})
noteWindow.loadFile('note.html')
}
function createTray() {
tray = new Tray(path.join(__dirname, 'assets/icon.png'))
const contextMenu = Menu.buildFromTemplate([
{ label: '显示主窗口', click: () => mainWindow.show() },
{ label: '退出', click: () => app.quit() }
])
tray.setToolTip('VueElectronNotes')
tray.setContextMenu(contextMenu)
}
app.whenReady().then(createMainWindow)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
ipcMain.handle('get-notes', () => {
return store.get('notes', [])
})
ipcMain.on('save-note', (event, note) => {
const notes = store.get('notes', [])
notes.push(note)
store.set('notes', notes)
mainWindow.webContents.send('update-notes', notes)
})
说明:
mainWindow
:主窗口,显示笔记列表noteWindow
:子窗口,用于新建笔记Tray
:系统托盘图标与菜单ipcMain
:主进程接收渲染进程消息
四、渲染进程与 Vue
preload.js
:
实例
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
getNotes: () => ipcRenderer.invoke('get-notes'),
saveNote: (note) => ipcRenderer.send('save-note', note),
onUpdateNotes: (callback) => ipcRenderer.on('update-notes', callback)
})
contextBridge.exposeInMainWorld('electronAPI', {
getNotes: () => ipcRenderer.invoke('get-notes'),
saveNote: (note) => ipcRenderer.send('save-note', note),
onUpdateNotes: (callback) => ipcRenderer.on('update-notes', callback)
})
src/App.vue
:
实例
<template>
<div>
<h1>笔记列表</h1>
<button @click="openNoteWindow">新建笔记</button>
<ul>
<li v-for="(note, index) in notes" :key="index">{{ note }}</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return { notes: [] }
},
methods: {
openNoteWindow() {
window.open('note.html', '新建笔记', 'width=400,height=300')
}
},
mounted() {
window.electronAPI.getNotes().then((notes) => {
this.notes = notes
})
window.electronAPI.onUpdateNotes((event, notes) => {
this.notes = notes
})
}
}
</script>
<div>
<h1>笔记列表</h1>
<button @click="openNoteWindow">新建笔记</button>
<ul>
<li v-for="(note, index) in notes" :key="index">{{ note }}</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return { notes: [] }
},
methods: {
openNoteWindow() {
window.open('note.html', '新建笔记', 'width=400,height=300')
}
},
mounted() {
window.electronAPI.getNotes().then((notes) => {
this.notes = notes
})
window.electronAPI.onUpdateNotes((event, notes) => {
this.notes = notes
})
}
}
</script>
note.html
+ note.js
:
note.html
:
实例
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>新建笔记</title></head>
<body>
<h2>新建笔记</h2>
<textarea id="note"></textarea><br>
<button id="saveBtn">保存</button>
<script src="note.js"></script>
</body>
</html>
<html>
<head><meta charset="UTF-8"><title>新建笔记</title></head>
<body>
<h2>新建笔记</h2>
<textarea id="note"></textarea><br>
<button id="saveBtn">保存</button>
<script src="note.js"></script>
</body>
</html>
note.js
:
实例
const saveBtn = document.getElementById('saveBtn')
saveBtn.addEventListener('click', () => {
const note = document.getElementById('note').value
if (note) {
window.electronAPI.saveNote(note)
window.close()
}
})
saveBtn.addEventListener('click', () => {
const note = document.getElementById('note').value
if (note) {
window.electronAPI.saveNote(note)
window.close()
}
})
说明:
note.html
是弹出窗口,用于输入笔记note.js
调用electronAPI.saveNote
发送到主进程- 主窗口会接收到
update-notes
消息更新列表
五、运行项目
开发模式:
npm run electron:serve
- Vue Dev Server + Electron 同时启动
- 可实时调试 UI
打包应用:
npm run electron:build
- 输出可执行文件到
dist_electron
- 支持 Windows/macOS/Linux
点我分享笔记