x***@126.com
x***@126.com
  • 发布:2021-03-01 09:59
  • 更新:2024-07-10 15:15
  • 阅读:2856

vue3.x+electron聊天程序|Electron跨平台聊天室

分类:uni-app

前言

随着Electron快速更新迭代及Vue3生态圈愈来愈完善,二者结合开发桌面端程序必然再一次受到开发者热捧。

上一次有给大家分享一个vue3开发移动端短视频实例,今天带来的是最新开发的一款electron+vue3桌面版搭建TIM/QQ聊天应用程序实战项目ElectronQchat。

vite2+vant3模仿抖音小视频|直播实例

img

vue3-electron-qchat 支持同时新开多个窗口、换肤等功能。

img

框架技术

  • 编码+技术:vscode | vue3.0+vuex4+vue-router@4
  • 跨端框架:electron11.2.3
  • UI组件库:ant-design-vue (蚂蚁桌面端vue3组件库)
  • 弹窗组件:v3layer(vue3自定义弹窗组件)
  • 滚动条组件:v3scroll(vue3自定义滚动条组件)
  • 打包工具:vue-cli-plugin-electron-builder
  • 按需引入:babel-plugin-import^1.13.3

项目结构

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

electron主进程入口

vue3+electron搭建的项目,根目录下有一个background.js,即主进程入口配置。

/**  
 * 主进程入口配置  
 */  

import { app, BrowserWindow, globalShortcut } from 'electron'  
// import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'  

import Windows from './module/windows'  

const isDevelopment = process.env.NODE_ENV !== 'production'  

async function createWindow() {  
  let window = new Windows()  

  window.listen()  
  window.createWin({isMainWin: true})  
  window.createTray()  
}  

app.on('window-all-closed', () => {  
  if (process.platform !== 'darwin') {  
    app.quit()  
  }  
})  

app.on('activate', () => {  
  if (BrowserWindow.getAllWindows().length === 0) createWindow()  
})  

app.on('ready', async () => {  
  createWindow()  
})  

// Exit cleanly on request from parent process in development mode.  
if (isDevelopment) {  
  if (process.platform === 'win32') {  
    process.on('message', (data) => {  
      if (data === 'graceful-exit') {  
        app.quit()  
      }  
    })  
  } else {  
    process.on('SIGTERM', () => {  
      app.quit()  
    })  
  }  
}

electron创建多窗体|父子modal窗口模式

项目支持同时新开多个窗口及modal窗口模式。只需简单调用公共函数createWin即可快速生成一个新窗口。

// 换肤窗口  
const handleSkinWin = () => {  
    createWin({  
        title: '换肤',  
        route: '/skin',  
        width: 720,  
        height: 475,  
        resize: false,  
    })  
}  

// 朋友圈窗口  
const handleFZoneWin = () => {  
    createWin({  
        title: '朋友圈',  
        route: '/fzone',  
        width: 550,  
        height: 700,  
        resize: false,  
    })  
}

支持如下参数配置:

export const winConfig = {  
    id: null,               // 窗口唯一id  
    background: '#fff',     // 背景色  
    route: '',              // 路由地址url  
    title: '',              // 标题  
    data: null,             // 传入数据参数  
    width: '',              // 窗口宽度  
    height: '',             // 窗口高度  
    minWidth: '',           // 窗口最小宽度  
    minHeight: '',          // 窗口最小高度  
    x: '',                  // 窗口相对于屏幕左侧坐标  
    y: '',                  // 窗口相对于屏幕顶端坐标  
    resize: true,           // 是否支持缩放  
    maximize: false,        // 最大化窗口  
    isMultiWin: false,      // 是否支持多开窗口(为true则会支持创建多个窗口)  
    isMainWin: false,       // 是否主窗口(为true则会替代之前主窗口)  
    parent: '',             // 父窗口(传入父窗口id)  
    modal: false,           // 模态窗口(需设置parent和modal选项)  
    alwaysOnTop: false,     // 是否置顶窗口  
}

由于篇幅原因,大家如果对实现过程感兴趣,可以去看看下面这篇文章。

electron+vue3搭建项目|创建多窗体模式

electron无边框窗口|自定义顶部菜单

项目整体采用无边框模式,开启frame:false即可。顶部导航栏及右上角按钮就需要自定义实现了。

img

设置-webkit-app-region:drag即可自定义拖拽区域,不过拖拽区域鼠标右键会有系统菜单。

img

可通过如下方法,在创建窗口的时候快速给屏蔽掉。

win.hookWindowMessage(278, () => {  
    win.setEnabled(false)  
    setTimeout(() => {  
        win.setEnabled(true)  
    }, 100)  

    return true  
})

出于篇幅缘故,大家如果对具体如何实现导航栏菜单感兴趣,可以去看看这篇分享。

electron实现无边框导航条|最大/小化/关闭按钮

electron模仿QQ托盘图标/闪烁

electron提供了Tray函数来创建系统托盘图标,大家可以通过定时器来实现闪烁效果。

img

img

需提前准备好两张大小一致的图标文件,一个透明背景就行。然后通过定时器来轮流显示图标。

// 创建系统托盘图标  
let tray = null  
let flashTimer = null  
let trayIco1 = path.join(__dirname, '../static/tray.ico')  
let trayIco2 = path.join(__dirname, '../static/tray-empty.ico')  

createTray() {  
    const trayMenu = Menu.buildFromTemplate([  
        {  
            label: '我在线上', icon: path.join(__dirname, '../static/icon-online.png'),  
            click: () => {...}  
        },  
        {  
            label: '忙碌', icon: path.join(__dirname, '../static/icon-busy.png'),  
            click: () => {...}  
        },  
        {  
            label: '隐身', icon: path.join(__dirname, '../static/icon-invisible.png'),  
            click: () => {...}  
        },  
        {  
            label: '离开', icon: path.join(__dirname, '../static/icon-offline.png'),  
            click: () => {...}  
        },  
        {type: 'separator'},  
        {  
            label: '关闭所有声音', click: () => {...},  
        },  
        {  
            label: '关闭头像闪动', click: () => {  
                this.flashTray(false)  
            }  
        },  
        {type: 'separator'},  
        {  
            label: '打开主窗口', click: () => {  
                try {  
                    for(let i in this.winLs) {  
                        let win = this.getWin(i)  
                        if(!win) return  
                        if(win.isMinimized()) win.restore()  
                        win.show()  
                    }  
                } catch (error) {  
                    console.log(error)  
                }  
            }  
        },  
        {  
            label: '退出', click: () => {  
                try {  
                    for(let i in this.winLs) {  
                        let win = this.getWin(i)  
                        if(win) win.webContents.send('win-logout')  
                    }  
                    app.quit()  
                } catch (error) {  
                    console.log(error)  
                }  
            }  
        },  
    ])  
    this.tray = new Tray(this.trayIco1)  
    this.tray.setContextMenu(trayMenu)  
    this.tray.setToolTip(app.name)  
    this.tray.on('double-click', () => {  
        // ...  
    })  
}  
// 托盘图标闪烁  
flashTray(flash) {  
    let hasIco = false  

    if(flash) {  
        if(this.flashTimer) return  
        this.flashTimer = setInterval(() => {  
            this.tray.setImage(hasIco ? this.trayIco1 : this.trayIco2)  
            hasIco = !hasIco  
        }, 500)  
    }else {  
        if(this.flashTimer) {  
            clearInterval(this.flashTimer)  
            this.flashTimer = null  
        }  
        this.tray.setImage(this.trayIco1)  
    }  
}  
// 销毁托盘图标  
destoryTray() {  
    this.flashTray(false)  
    this.tray.destroy()  
    this.tray = null  
}

electron快速打包配置

vue3和electron创建的项目,目录下会有一个vue.config.js配置文件。里面可以进行一些vue3配置及electron-builder打包配置。

/**  
 * @Desc      vue3项目配置文件  
 * @Create   andy by 2021-02  Q:282310962  wx:xy190310  
 */  

const path = require('path')  

module.exports = {  
    // 基本路径  
    // publicPath: '/',  

    // 输出文件目录  
    // outputDir: 'dist',  

    // assetsDir: '',  

    // 环境配置  
    devServer: {  
        // host: 'localhost',  
        // port: 8080,  
        // 是否开启https  
        https: false,  
        // 编译完是否打开网页  
        open: false,  

        // 代理配置  
        // proxy: {  
        //     '^/api': {  
        //         target: '<url>',  
        //         ws: true,  
        //         changeOrigin: true  
        //     },  
        //     '^/foo': {  
        //         target: '<other_url>'  
        //     }  
        // }  
    },  

    // webpack配置  
    chainWebpack: config => {  
        // 配置路径别名  
        config.resolve.alias  
            .set('@', path.join(__dirname, 'src'))  
            .set('@assets', path.join(__dirname, 'src/assets'))  
            .set('@components', path.join(__dirname, 'src/components'))  
            .set('@module', path.join(__dirname, 'src/module'))  
            .set('@plugins', path.join(__dirname, 'src/plugins'))  
            .set('@layouts', path.join(__dirname, 'src/layouts'))  
            .set('@views', path.join(__dirname, 'src/views'))  
    },  

    // 插件配置  
    pluginOptions: {  
        electronBuilder: {  
            // 配置后可以在渲染进程使用ipcRenderer  
            nodeIntegration: true,  

            // 项目打包参数配置  
            builderOptions: {  
                "productName": "electron-qchat", //项目名称 打包生成exe的前缀名  
                "appId": "com.example.electronqchat", //包名  
                "compression": "maximum", //store|normal|maximum 打包压缩情况(store速度较快)  
                "artifactName": "${productName}-${version}-${platform}-${arch}.${ext}", //打包后安装包名称  
                // "directories": {  
                //     "output": "build", //输出文件夹(默认dist_electron)  
                // },  
                "asar": false, //asar打包  
                // 拷贝静态资源目录到指定位置  
                "extraResources": [  
                    {  
                        "from": "./static",  
                        "to": "static"  
                    },  
                ],  
                "nsis": {  
                    "oneClick": false, //一键安装  
                    "allowToChangeInstallationDirectory": true, //允许修改安装目录  
                    "perMachine": true, //是否开启安装时权限设置(此电脑或当前用户)  
                    "artifactName": "${productName}-${version}-${platform}-${arch}-setup.${ext}", //打包后安装包名称  
                    "deleteAppDataOnUninstall": true, //卸载时删除数据  
                    "createDesktopShortcut": true, //创建桌面图标  
                    "createStartMenuShortcut": true, //创建开始菜单图标  
                    "shortcutName": "ElectronQChat", //桌面快捷键图标名称  
                },  
                "win": {  
                    "icon": "./static/shortcut.ico", //图标路径  
                }  
            }  
        }  
    }  
}

注意事项

1、项目路径最好不能含有中文,否则打包会失败!
2、最好不要使用getCurrentInstance来操作router或store,否则打包会报错!
3、在渲染进程中使用ipcRenderer或remote模块,记得在创建窗体的时候配置nodeIntegration: true和enableRemoteModule: true
否则会出现如下错误提示:Uncaught TypeError: fs.existsSync is not a function
4、如果打包后图标或外部dll无效,记得在打包的时候配置静态资源转移extraResources

// 拷贝静态资源目录到指定位置  
"extraResources": [  
    {  
        "from": "./static",  
        "to": "static"  
    },  
]

ok,以上就是vue3+electron开发客户端聊天软件的一些分享,希望对大家有些帮助!

链接:https://juejin.cn/post/6933871014937886727/
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2 关注 分享
6***@qq.com y***@outlook.com

要回复文章请先登录注册

x***@126.com

x***@126.com (作者)

最新版electron31+vite5+vue3仿微信客户端exe聊天室模板。
![img](https://image-static.segmentfault.com/621/032/62103219-668c99a8ab1ba_fix732)
https://www.cnblogs.com/xiaoyan2017/p/18290962
2024-07-10 15:15
x***@126.com

x***@126.com (作者)

electron-chatgpt智能会话实例
[https://ask.dcloud.net.cn/article/40582](https://ask.dcloud.net.cn/article/40582)
2023-07-07 07:30