
最终目标
创建类似360、腾讯电脑管家的气泡悬浮球,并且实现拖动,点击气泡框显示AI聊天对话框,可以和AI进行通话。并创建系统托盘应用图标,实现应用显示、隐藏,退出功能。
使用工具
1、electron-vite脚手架 2、MaxKB 3、Tray
实现过程
1、使用electron-vite脚手架工具搭建项目框架
npm create @quick-start/electron@latest
目录结构如下,主要是src目录下的,main是主进程,主要作用是创建electron应用窗体,并且实现一些监听,操作应用,preload是预加载进程,可以将主进程的一些东西暴露给渲染进程,作为桥梁的作用;renderer是作为渲染进程,是具体的页面显示,这里使用的是vue,所以renderer下面其实就是完整的vue工程。
2、首先是创建应用,在主进程创建BrowserWindow实例,定义应用宽高,type类型选择toolbar工具栏应用,frame设置false为无边框。
// Create the browser window. mainWindow = new BrowserWindow({ // width: 900, // height: 670, show: false, transparent: true, backgroundColor: '#00000000', autoHideMenuBar: true, width: 80, height: 80, type: 'toolbar', //创建的窗口类型为工具栏窗口 frame: false, //要创建无边框窗口 resizable: false, //禁止窗口大小缩放 // alwaysOnTop: true, // show: false, ...(process.platform === 'linux' ? { icon } : {}), webPreferences: { nodeIntegration: true, // 或 process.env.NODE_ENV !== 'production', contextIsolation: false, preload: join(__dirname, '../preload/index.js'), sandbox: false } })
设置框体在桌面屏幕位置
const { left, top } = { left: screen.getPrimaryDisplay().workAreaSize.width - 90, top: screen.getPrimaryDisplay().workAreaSize.height - 90 } mainWindow.setPosition(left, top) // 设置悬浮球位置 mainWindow.setVisibleOnAllWorkspaces(true) // 显示在所有工作区
3、创建系统托盘,使用electron自带的Tray类,并且定义托盘操作栏菜单,并且定义托盘图标双击事件。
import icon from '../../resources/icon.png?asset'
// 创建系统托盘图标和菜单 tray = new Tray(icon); const trayMenu = Menu.buildFromTemplate([ { label: '显示气泡框', click: () => { mainWindow.show(); } }, { label: '隐藏气泡框', click: () => { mainWindow.hide(); } }, { type: 'separator' }, { label: '退出', click: () => { if (tray) tray.destroy(); app.exit(); } } ]); tray.setContextMenu(trayMenu); tray.setToolTip('AI助手'); tray.on('double-click', () => { if(mainWindow.isVisible()){ mainWindow.hide() }else{ mainWindow.show() } });
4、编写渲染进程页面代码
首先设置body背景透明,使用脚手架创建的工程会设置body的背景色,这里我们需要删掉,或者直接在index.html页面设置body背景透明
为了让窗体能够拖动,设置样式-webkit-app-region: drag;这样设置了之后整个页面的点击事件将会失效,所以设置app节点样式为no-drag,并且body设置内边框,这样窗体边缘可以拖动,中间区域也不影响点击事件。
App.vue页面绘制页面
<script setup lang="ts"> import { ref } from 'vue' const chatVisible = ref(false) //打开聊天窗口 function openChatDialog() { chatVisible.value = !chatVisible.value //和主进程通信修改窗体大小 window.electron.ipcRenderer.send('openChat') } //关闭聊天窗口 function closeChatDialog() { chatVisible.value = !chatVisible.value window.electron.ipcRenderer.send('closeChat') } </script> <template> <div class="ball" @click="openChatDialog" v-if="!chatVisible" title="AI助手"> AI </div> <div v-else class="chat"> <span class="close-icon" @click="closeChatDialog" title="关闭">X</span> <iframe src="http://10.88.99.12:8980/ui/chat/f1fe745724ef2929?mode=mobile" style="width: 100%; height: 100%;" frameborder="0" allow="microphone"> </iframe> </div> </template> <style scoped lang="scss"> .ball { width: 60px; height: 60px; border-radius: 50%; display: flex; justify-content: center; align-items: center; background-color: rgba(15, 14, 62, 0.7); } .chat { background-color: #fff; height: 97vh; width: 96vw; .close-icon{ color:black; font-size: 20px; cursor: pointer; position: absolute; right:55px; top:22px; } } </style>
在主进程添加监听渲染进程的点击监听事件,监听放在app.whenReady里面
//动态改变窗体大小——显示聊天框 ipcMain.on('openChat', () => { let position = mainWindow.getPosition() logger.info('窗体位置:'+position) mainWindow.setContentSize(400, 700) // const { left, top } = { left: screen.getPrimaryDisplay().workAreaSize.width - 420, top: screen.getPrimaryDisplay().workAreaSize.height - 720 } mainWindow.setPosition(position[0]-320, position[1]-620) // 设置悬浮球位置 logger.info('ok:打开聊天框') console.log('ok:打开聊天框') }) //动态改变窗体大小——显示气泡框 ipcMain.on('closeChat', () => { let position = mainWindow.getPosition() logger.info('窗体位置:'+position) mainWindow.setContentSize(80, 80) // const { left, top } = { left: screen.getPrimaryDisplay().workAreaSize.width - 90, top: screen.getPrimaryDisplay().workAreaSize.height - 90 } mainWindow.setPosition(position[0]+320, position[1]+620) // 设置悬浮球位置 logger.info('ok:关闭聊天框') console.log('ok:关闭聊天框') })
5、这里AI使用的是MaxKB,嵌入方式是MaxKB使用iframe的方式,这里由于electron的csp规则限制,需要在渲染进程的index.html页面修改csp安全策略,将MaxKB的地址添加进去,并且最好使用https,我这里使用的http会有警告。
6、运行效果
可以拖动,点击之后显示AI聊天对话框
点击X可以关闭对话框,显示为气泡框。系统托盘显示图标。
右键图标可以显示操作菜单,并且双击图标可以快速显示、隐藏气泡框。
7、打包
运行build:win可以打windows包,还可以打mac和linux的包。node环境建议22.0.0以上,不然打包的时候会报错,最终会形成一个安装包,双击安装在桌面创建一个应用图标。