35

项目说明:

electron-vChat聊天是一个基于electron+electron-vue+vue+vuex+Nodejs+vue-router等技术开发的高仿微信pc客户端界面聊天室项目,实现消息发送/表情,图片/视频预览,拖拽上传/粘贴截图发送/微信dll截图,右键菜单、朋友圈/红包/换肤等功能。

预览图:

034360截图20200108115113391.png

技术框架:

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

001360截图20200108101448499.png

002360截图20200108101513050.png

003360截图20200108101537650.png

005360截图20200108101943394.png

006360截图20200108103216338.png

007360截图20200108103303225.png

如上图:可以自由切换桌面端聊天背景皮肤

009360截图20200108102231769.png

011360截图20200108102556698.png

013360截图20200108103747272.png

015360截图20200108104156775.png

018360截图20200108104532767.png

019360截图20200108105155294.png

020360截图20200108105937133.png

024360截图20200108110609181.png

025360截图20200108110820571.png

027360截图20200108111356238.png

029360截图20200108113415376.png

031360截图20200108114130270.png

Electron 是由Github开发,用HTML,CSS和JavaScript来构建跨平台桌面应用程序的一个开源库。
https://electronjs.org/
至于如何搭建开发环境及使用electron-vue,可自行去查阅官网及搜资料
基于vue语法来构造 electron 应用程序的样板代码。

https://electron.org.cn/vue/i...
https://simulatedgreg.gitbook...

electron主进程:创建及配置

通过electron里的BrowserWindow对象创建和控制浏览器窗口
src目录下有main、renderer两个文件夹,分别是主进程及渲染进程,配置窗口修改src/main/index.js文件即可。


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()
        }
    })
    
    ...
    apptray.createTray()
}

app.on('ready', createMainWin)

app.on('activate', () => {
    if(mainWin === null) {
        createMainWin()
    }
})

...

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(flash) {
    let hasIco = false

    if(flash) {
      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
  }
}

点击窗口关闭,监听close事件,判断是否最小化到托盘

// 点击关闭最小到托盘判断
mainWin.on('close', (e) => {
    if(logined && !forceQuit) {
        e.preventDefault()
        mainWin.hide()
    }else {
        mainWin = null
        app.quit()
    }
})

electron渲染进程:主入口页面配置

/**
 * @Desc   主入口页面JS
 * @about  Q:282310962  wx:xy190310
 */

import Vue from 'vue'
import axios from 'axios'

import App from './App'
import router from './router'
import store from './store'

// 引入组件配置
import $components from './components'
Vue.use($components)

if (!process.env.IS_WEB) Vue.use(require('vue-electron'))
Vue.http = Vue.prototype.$http = axios


/* eslint-disable no-new */
new Vue({
  components: { App },
  router,
  store,
  template: '<App/>'
}).$mount('#app')

主窗口页面分为侧边栏+主布局,主布局顶部里含有最大/小化、关闭按钮

<template>
  <div id="app">
    <div class="elv-container" :style="$store.state.winSkin && {'background-image': 'url('+$store.state.winSkin+')'}">
      <div class="elv-wrapper flexbox">
        <!-- //侧边栏 -->
        <side-bar v-if="!$route.meta.hideSideBar" />

        <!-- //主布局 -->
        <div class="elv-mainbx flex1 flexbox flex-col">
          <!-- ...顶部按钮 -->
          <win-bar />
          
          <keep-alive>
            <router-view></router-view>
          </keep-alive>
        </div>
      </div>
    </div>
  </div>
</template>

electron无边框窗口实现拖动、最大/小化、关闭功能

配置frame: false就能实现无边框窗体,拖动窗口功能需另行处理
360截图20200109013431570.png

  • 通过mousedown、mousemove等事件处理
  • 设置需要拖动区css属性 -webkit-app-region

设置css -webkit-app-region: drag; 就能实现拖动窗口
设置-webkit-app-region: drag后,下面的元素不能点击操作,可通过设置需点击元素no-drag即可。

顶部winbar.vue组件

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()
        }
    }
}

electron编辑器光标处插入表情、div可编辑contenteditable="true"双向绑定 、electron截图功能

vue如何实现编辑框contenteditable光标处插入动态表情,这里不多介绍,可以去看之前的一篇分享文章。
electron+vue实现div contenteditable功能|截图

好了,基于electron+vue开发仿微信桌面聊天实例就分享到这里,希望能有点点帮助!!💪💪

最后分享个uniapp+vue实例项目
uniapp即时聊天|vue+uniapp仿微信app聊天实例|uniapp仿微信界面


xiaoyan2017
765 声望314 粉丝

web前端开发爱好者,专注于前端h5、jquery、vue、react、angular等技术研发实战项目案例。