electron-vchat客户端聊天实例是基于electron vue vuex Node vue-router等技术开发的仿制微信pc桌面聊天项目。实现了消息发送 /表情(光标处插入表情),图片 /视频预览,拖拽上传 /粘贴截图发送 /微信 dll 截图,右键菜单、朋友圈 /红包 /换肤等功能。
技术框架
- 框架技术:electron electron-vue vue
- 状态管理:Vuex
- 地址路由:Vue-router
- 字体图标:阿里 iconfont 字体图标库
- 弹窗插件:wcPop
- 打包工具:electron-builder
- 图片组件:vue-photo-preview
- 视频组件:vue-video-player
公共组件引入配置
代码语言:javascript复制/**
* @Desc 公共及全局组件配置
* @about Q:282310962 wx:xy190310
*/
// 引入公共组件
import winBar from './components/winbar'
import sideBar from './components/sidebar'
// 引入公共样式
import './assets/fonts/iconfont.css'
import './assets/css/reset.css'
import './assets/css/layout.css'
// 引入弹窗wcPop
import wcPop from './assets/js/wcPop/wcPop'
import './assets/js/wcPop/skin/wcPop.css'
// 引入图片预览组件vue-photo-preview
import photoView from 'vue-photo-preview'
import 'vue-photo-preview/dist/skin.css'
// 引入视频播放组件vue-video-player
import videoPlayer from 'vue-video-player'
import 'video.js/dist/video-js.css'
const install = Vue => {
// 注册组件
Vue.component('win-bar', winBar)
Vue.component('side-bar', sideBar)
// 应用实例
Vue.use(photoView, {
// loop: false, //循环
// fullscreenEl: true, //全屏
// arrowEl: true, //左右按钮
})
Vue.use(videoPlayer)
}
export default install
Electron 是由 Github 开发,用 HTML,CSS 和 JavaScript 来构建跨平台桌面应用程序的一个开源库。更多的介绍及搭建项目环境可去官网查阅。
https://electronjs.org/
https://electron.org.cn/vue/index.html
https://github.com/SimulatedGREG/electron-vue
electron主进程创建窗口
通过electron提供的BrowserWindow对象创建窗体,electron-vue构建项目后,主进程入口页面是src/main/index.js
代码语言:javascript复制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实现系统托盘图标及闪烁效果
托盘图标闪烁是通过两个ico文件设置时间戳交替切换
代码语言:javascript复制/**
* electron创建系统托盘图标
*/
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
}
}
renderer渲染进程里面的页面写法和vue一样,这里不作过多介绍了。
electron实现自定义顶部最大/小化、关闭按钮、无外框窗口
electron 中配置 frame: false 后,就能去除原窗体顶部,原先的顶部操作栏就没有了,需要自定义配置。
代码语言:javascript复制// 置顶窗口
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)
}
},
项目中使用的是局部拖动css属性 -webkit-app-region: drag
注意:默认设置-webkit-app-region: drag后,下面的元素不能点击操作,可通过设置需点击元素no-drag即可。
electron实现微信编辑器光标处插入表情 截图功能
采用vue中设置div可编辑contenteditable="true" 自定义双向绑定v-model ,定位光标处插入动态表情。
每次插入内容光标定位到最后可参考
代码语言:javascript复制function setLastCaret(obj) {
console.log(obj)
console.log(window.getSelection)
console.log(document.selection)
if (window.getSelection) { //ie11 10 9 ff safari
obj.focus(); //解决ff不获取焦点无法定位问题
var range = window.getSelection(); //创建range
range.selectAllChildren(obj); //range 选择obj下所有子内容
range.collapseToEnd(); //光标移至最后
} else if (document.selection) { //ie10 9 8 7 6 5
var range = document.selection.createRange(); //创建选择对象
//var range = document.body.createTextRange();
range.moveToElementText(obj); //range定位到obj
range.collapse(false); //光标移至最后
range.select();
}
}
截图功能是通过Node中的execFile方法执行exe文件,exe调用同级目录下的微信截图dll,调出截图工具
代码语言:javascript复制// 可编辑div contenteditable中粘贴发送图片
submitPasteImage{
let that = this
this.$refs.editor.addEventListener('paste', function(e) {
let cbd = e.clipboardData
let ua = window.navigator.userAgent
if(!(e.clipboardData && e.clipboardData.items)) return
if(cbd.items && cbd.items.length === 2 && cbd.items[0].kind === "string" && cbd.items[1].kind === "file" &&
cbd.types && cbd.types.length === 2 && cbd.types[0] === "text/plain" && cbd.types[1] === "Files" &&
ua.match(/Macintosh/i) && Number(ua.match(/Chrome/(d{2})/i)[1]) < 49){
return;
}
for(var i = 0; i < cbd.items.length; i ){
var item = cbd.items[i];
console.log(item);
console.log(item.kind);
if(item.kind == "file"){
var blob = item.getAsFile();
if(blob.size === 0){
return;
}
// 插入图片记录
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = function(){
var _img = this.result;
// ***返回图片给父组件
that.$emit('pasteFn', _img)
}
}
}
})
},
这里也不作过多详细介绍,之前有过这方面的分享介绍
https://segmentfault.com/a/1190000021510872
基于electron vue开发聊天实例项目 就介绍差不多了,希望能有些帮助~~