vue-electron仿微信电脑端聊天实例|electron即时聊天IM



  • ElectronVchat聊天项目是运用桌面端技术electron+vue+vuex开发的仿制微信聊天室实战案例,实现消息发送/表情,图片/视频预览,拖拽上传/粘贴截图发送/微信dll截图,右键菜单、朋友圈/红包/换肤等功能。

    009360截图20200108102231769.png

    技术栈

    • 运用技术:electron + electron-vue + vue
    • 状态管理:Vuex
    • 地址路由:Vue-router
    • 字体图标:阿里iconfont字体图标库
    • 弹窗插件:wcPop
    • 打包工具:electron-builder
    • 图片预览:vue-photo-preview
    • 视频组件:vue-video-player

    Electron 是由 Github 团队 开发,用 HTML,CSS 和 JavaScript 来构建跨平台桌面应用程序的一个开源库。

    https://electronjs.org/

    https://electron.org.cn/vue/index.html

    https://github.com/SimulatedGREG/electron-vue

    001360截图20200108101448499.png

    002360截图20200108101513050.png

    006360截图20200108103216338.png

    007360截图20200108103303225.png

    011360截图20200108102556698.png

    013360截图20200108103747272.png

    015360截图20200108104156775.png

    016360截图20200108104248455.png

    018360截图20200108104532767.png

    019360截图20200108105155294.png

    020360截图20200108105937133.png

    021360截图20200108110026102.png

    024360截图20200108110609181.png

    025360截图20200108110820571.png

    026360截图20200108111126868.png

    029360截图20200108113415376.png

    031360截图20200108114130270.png

    033360截图20200108114221398.png

    electron主进程创建窗口

    electron-vue构建项目后,src目录下有main/renderer主/渲染线程两个文件夹,主进程入口页面是src/main/index.js
    通过electron提供的BrowserWindow对象创建窗体

    /**
     * @Desc   主线程  Create by andy on 2019/12/26
     * @about   Q:282310962  wx:xy190310
     */
    
    import { BrowserWindow, app, ipcMain, Tray, Menu } from 'electron'
    
    // 引入主线程公共配置
    import Common from './utils/common'
    
    /**
     * Set `__static` path to static files in production
     * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
     */
    if (process.env.NODE_ENV !== 'development') {
      global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
    }
    
    let mainWin
    let tray
    let forceQuit = false
    let logined = false
    
    /**
     * 创建主窗口
     */
    function createMainWin() {
      mainWin = new BrowserWindow({
        // 背景颜色
        // backgroundColor: '#ebebeb',
        width: Common.WIN_SIZE_MAIN.width,
        height: Common.WIN_SIZE_MAIN.height,
        title: Common.WIN_TITLE,
        useContentSize: true,
        autoHideMenuBar: true,
        // 无边框窗口
        frame: false,
        resizable: true,
        // 窗口创建的时候是否显示. 默认值为true
        show: false,
        webPreferences: {
          // devTools: false,
          webSecurity: false
        }
      })
    
      mainWin.setMenu(null)
      mainWin.loadURL(Common.WIN_LOAD_URL())
    
      mainWin.once('ready-to-show', () => {
        mainWin.show()
        mainWin.focus()
      })
    
      // 判断最小化到系统托盘
      mainWin.on('close', (e) => {
        if(logined && !forceQuit) {
          e.preventDefault()
          mainWin.hide()
        }else {
          mainWin = null
          app.quit()
        }
      })
    
      initialIPC()
    }
    
    app.on('ready', createMainWin)
    
    app.on('activate', () => {
      if(mainWin === null) {
        createMainWin()
      }
    })
    
    app.on('before-quit', () => {
      forceQuit = true
    })
    
    app.on('window-all-closed', () => {
      if(process.platform !== 'darwin') {
        app.quit()
      }
    })
    
    ...
    

    electron系统托盘图标及闪烁效果

    副本--360截图20200108115525683.png

    /**
     * 托盘图标事件
     */
    let flashTrayTimer = null
    let trayIco1 = `${__static}/icon.ico`
    let trayIco2 = `${__static}/empty.ico`
    let apptray = {
      // 创建托盘图标
      createTray() {
        tray = new Tray(trayIco1)
        const menu = Menu.buildFromTemplate([
          {
            label: '打开主界面',
            icon: `${__static}/tray-ico1.png`,
            click: () => {
              if(mainWin.isMinimized()) mainWin.restore()
              mainWin.show()
              mainWin.focus()
              
              this.flashTray(false)
            }
          },
          {
            label: '关于',
          },
          {
            label: '退出',
            click: () => {
              if(process.platform !== 'darwin') {
                mainWin.show()
                // 清空登录信息
                mainWin.webContents.send('clearLoggedInfo')
                
                forceQuit = true
                mainWin = null
                app.quit()
              }
            }
          },
        ])
        tray.setContextMenu(menu)
        tray.setToolTip('electron-vchat v1.0.0')
    
        // 托盘点击事件
        tray.on('click', () => {
          if(mainWin.isMinimized()) mainWin.restore()
          mainWin.show()
          mainWin.focus()
    
          this.flashTray(false)
        })
      },
      // 托盘图标闪烁
      flashTray(bool) {
        let hasIco = false
    
        if(bool) {
          if(flashTrayTimer) return
          flashTrayTimer = setInterval(() => {
            tray.setImage(hasIco ? trayIco1 : trayIco2)
            hasIco = !hasIco
          }, 500)
        }else {
          if(flashTrayTimer) {
            clearInterval(flashTrayTimer)
            flashTrayTimer = null
          }
    
          tray.setImage(trayIco1)
        }
      },
      // 销毁托盘图标
      destroyTray() {
        this.flashTray(false)
        tray.destroy()
        tray = null
      }
    }
    

    electron设置无边框窗口

    只需在BrowserWindow 对象中 设置 frame: false 就能实现无边框窗体,但是拖动窗体需要另外处理。

    import { app, remote, ipcRenderer } from 'electron'
    import { mapState, mapMutations } from 'vuex'
    
    let currentWin = remote.getCurrentWindow()
    
    export default {
        props: {
            title: String,
        },
        data () {
            return {// 是否置顶
                isAlwaysOnTop: false,
                // 窗口是否可以最小化
                isMinimizable: true,
                // 窗口是否可以最大化
                isMaximizable: true,
            }
        },
        computed: {
            ...mapState(['isWinMaxed'])
        },
        mounted() {if(!currentWin.isMinimizable()) {
                this.isMinimizable = false
            }
            if(!currentWin.isMaximizable()) {
                this.isMaximizable = false
            }
            if(this.isWinMaxed && currentWin.isMaximizable()) {
                currentWin.maximize()
            }
    
            // 监听是否最大化
            currentWin.on('maximize', () => {
                this.SET_WINMAXIMIZE(true)
            })
            currentWin.on('unmaximize', () => {
                this.SET_WINMAXIMIZE(false)
            })
        },
        methods: {
            ...mapMutations(['SET_WINMAXIMIZE']),
    
            // 置顶窗口
            handleFixTop() {
                this.isAlwaysOnTop = !this.isAlwaysOnTop
                currentWin.setAlwaysOnTop(this.isAlwaysOnTop)
            },
    
            // 最小化
            handleMin() {
                currentWin.minimize()
            },
    
            // 最大化
            handleMax() {
                if(!currentWin.isMaximizable()) return
                if(currentWin.isMaximized()) {
                    currentWin.unmaximize()
                    this.SET_WINMAXIMIZE(false)
                }else {
                    currentWin.maximize()
                    this.SET_WINMAXIMIZE(true)
                }
            },
    
            // 关闭
            handleQuit() {
                currentWin.close()
            }
        }
    }
    
    • 设置-webkit-app-region: drag后,下面的元素不能点击操作,可通过设置需点击元素no-drag即可。*

    electron实现微信编辑器插入表情

    vue中设置div编辑状态 contenteditable="true" 自定义双向绑定v-model ,定位光标处插入动态表情。
    副本--360截图20200107160057637.png

    electron实现截图功能思路:通过Node调用execFile方法去执行exe文件,exe调用同级目录下的微信截图dll,调出截图工具,另外截图还可以粘贴至编辑器发送。

    大家可以去参看这篇分享:https://segmentfault.com/a/1190000021510872

    最后分享个taro+react实例项目
    uni-app聊天室IM实例|vue+uniapp仿微信即时聊天|uniapp仿微信App界面


Log in to reply