N
O
D
E
M
E
D
I
A
Thinking
首页
产品
文档
博客
订单
文档
基于Vue开发前端
28 次浏览
2026年 6月 1日 下午5:10
在快速集成中,我们使用官方推荐的Electron Forge创建程序。可以用来开发react但是需要很多配置,我们在这个例子中换一个更简单的脚手架: [create-electron](https://www.npmjs.com/package/%40quick-start/create-electron) ## 1.创建项目 ```bash npm create @quick-start/electron ``` ```bash > npx > "create-electron" ✔ Project name: … electron-app-vue ✔ Select a framework: › vue ✔ Add TypeScript? … No / Yes ✔ Add Electron updater plugin? … No / Yes ✔ Enable Electron download mirror proxy? … No / Yes Scaffolding project in /Users/aliang/electron-app-vue... Done. Now run: cd electron-app-vue npm install npm run dev ``` 编辑器打开项目,可以看到目录结构如下  ## 2.安装扩展 执行命令 ```bash npm i nodeplayer-addon ``` ## 3.编辑 src/main/index.js 文件 ```js import { app, shell, BrowserWindow, ipcMain } from 'electron' import { join } from 'path' import { electronApp, optimizer, is } from '@electron-toolkit/utils' import icon from '../../resources/icon.png?asset' import NodePlayer from 'nodeplayer-addon' let mainWindow = null function createWindow() { mainWindow = new BrowserWindow({ width: 1024, height: 768, show: false, autoHideMenuBar: true, ...(process.platform === 'linux' ? { icon } : {}), webPreferences: { preload: join(__dirname, '../preload/index.js'), sandbox: false } }) mainWindow.on('ready-to-show', () => { mainWindow.show() }) mainWindow.webContents.setWindowOpenHandler((details) => { shell.openExternal(details.url) return { action: 'deny' } }) if (is.dev && process.env['ELECTRON_RENDERER_URL']) { mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL']) } else { mainWindow.loadFile(join(__dirname, '../renderer/index.html')) } } app.whenReady().then(() => { electronApp.setAppUserModelId('com.electron') app.on('browser-window-created', (_, window) => { optimizer.watchWindowShortcuts(window) }) createWindow() NodePlayer.registerIpc(ipcMain, { getWindow: () => mainWindow, licensePath: app.isPackaged ? join(process.resourcesPath, 'license.dat') : join(__dirname, '../../license.dat') }) app.on('activate', function () { if (BrowserWindow.getAllWindows().length === 0) createWindow() }) }) app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit() } }) ``` ## 4. 编辑src/preload/index.js ```js import { contextBridge, ipcRenderer } from 'electron' import { electronAPI } from '@electron-toolkit/preload' const playerAPI = { createPlayer: (id) => ipcRenderer.invoke('player:create', id), startPlayer: (id, url) => ipcRenderer.invoke('player:start', id, url), stopPlayer: (id) => ipcRenderer.invoke('player:stop', id), destroyPlayer: (id) => ipcRenderer.invoke('player:destroy', id), startRecord: (id, filePath) => ipcRenderer.invoke('player:startRecord', id, filePath), stopRecord: (id) => ipcRenderer.invoke('player:stopRecord', id), onEvent: (id, callback) => { const channel = `player:event:${id}` const handler = (_event, data) => callback(data) ipcRenderer.on(channel, handler) return () => ipcRenderer.removeListener(channel, handler) }, onInfo: (id, callback) => { const channel = `player:info:${id}` const handler = (_event, info) => callback(info) ipcRenderer.on(channel, handler) return () => ipcRenderer.removeListener(channel, handler) }, onData: (id, callback) => { const channel = `player:data:${id}` const handler = (_event, data) => callback(data) ipcRenderer.on(channel, handler) return () => ipcRenderer.removeListener(channel, handler) } } if (process.contextIsolated) { try { contextBridge.exposeInMainWorld('electron', electronAPI) contextBridge.exposeInMainWorld('electronAPI', playerAPI) } catch (error) { console.error(error) } } else { window.electron = electronAPI window.electronAPI = playerAPI } ``` ## 5.创建播放组件src/renderer/src/components/VideoPlayerView.vue ```vue <script setup> import { ref, shallowRef } from 'vue' import VideoPlayer from 'nodeplayer-addon/video-player' const url = ref('rtsp://') const status = ref('') const playing = ref(false) const videoRef = ref(null) const playerRef = shallowRef(null) async function handlePlay() { if (!url.value.trim()) return const video = videoRef.value if (!video) return const player = new VideoPlayer(video, 'player-1', { onStatus(_id, text) { status.value = text }, onRecord(_id, recording, _msg) { if (recording) { status.value = 'Recording...' } } }) playerRef.value = player playing.value = true await player.start(url.value.trim()) } async function handleStop() { const player = playerRef.value if (player) { await player.stop() playerRef.value = null } playing.value = false status.value = '' } function onKeydown(e) { if (e.key === 'Enter' && !playing.value) handlePlay() } </script> <template> <div class="player-container"> <div class="player-toolbar"> <input type="text" class="url-input" :value="url" :disabled="playing" placeholder="rtsp:// or rtmp://" @input="url = $event.target.value" @keydown="onKeydown" /> <button v-if="!playing" class="btn btn-play" :disabled="!url.trim()" @click="handlePlay"> ▶ Play </button> <button v-else class="btn btn-stop" @click="handleStop">■ Stop</button> </div> <div class="player-video-wrapper"> <video ref="videoRef" class="player-video" autoplay muted playsinline /> <div v-if="status" class="player-status">{{ status }}</div> </div> </div> </template> ``` ## 6.加载组件 src/renderer/src/App.vue ```vue <script setup> import Versions from './components/Versions.vue' import VideoPlayerView from './components/VideoPlayerView.vue' </script> <template> <div class="app"> <header class="app-header"> <h1>NodePlayer</h1> </header> <main class="app-main"> <VideoPlayerView /> </main> <footer class="app-footer"> <Versions /> </footer> </div> </template> ``` ## 运行效果  ## 联系客服索取demo源码 - QQ: 281269007 - Email: service@nodemedia.cn
嘿,我是小R,需要帮助随时找我哦
QQ客服:281269007
邮件支持
扫码加微信
回到顶部