Vue通过配置WebSocket并实现群聊功能


Posted in Javascript onDecember 31, 2019

原文链接:https://juejin.im/post/5e08d53a6fb9a0162b7f4bad

写JQuery项目时,使用websocket很简单,不用去考虑模块化,组件之间的访问问题,面向文档编程即可,在Vue项目中使用时,远远没有想象中的那么简单,需要考虑很多场景,本篇文章将与各位开发者分享下 vue-native-websocket 库的使用以及配置,用其实现群聊功能。先看下最终实现的效果

Vue通过配置WebSocket并实现群聊功能 

安装依赖

本文中对于 vue-native-websocket 库的讲解,项目中配置了vuex,对其不了解的开发者请移步官方文档,如果选择继续阅读本篇文章会比较吃力。

vue-native-websocket安装
# yarn | npm 安装
yarn add vue-native-websocket | npm install vue-native-websocket --save

Vue通过配置WebSocket并实现群聊功能

安装成功

配置插件

在 main.js 中进行导入

import VueNativeSock from 'vue-native-websocket'

使用 VueNativeSock 插件,并进行相关配置

// main.js
// base.lkWebSocket为你服务端websocket地址
Vue.use(VueNativeSock,base.lkWebSocket,{
 // 启用Vuex集成,store的值为你的vuex
 store: store,
 // 数据发送/接收使用使用json格式
 format: "json",
 // 开启自动重连
 reconnection: true,
 // 尝试重连的次数
 reconnectionAttempts: 5,
 // 重连间隔时间
 reconnectionDelay: 3000,
 // 将数据进行序列化,由于启用了json格式的数据传输这里需要进行重写
 passToStoreHandler: function (eventName, event) {
 if (!eventName.startsWith('SOCKET_')) { return }
 let method = 'commit';
 let target = eventName.toUpperCase();
 let msg = event;
 if (this.format === 'json' && event.data) {
 msg = JSON.parse(event.data);
 if (msg.mutation) {
 target = [msg.namespace || '', msg.mutation].filter((e) => !!e).join('/');
 } else if (msg.action) {
 method = 'dispatch';
 target = [msg.namespace || '', msg.action].filter((e) => !!e).join('/');
 }
 }
 this.store[method](target, msg);
 this.store.state.socket.message = msg;
 }
});

vuex的相关配置:mutations和actions添加相关函数

// vuex配置文件
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

export default new Vuex.Store({
 state: {
 token:"",
 userID:"",
 // 用户头像
 profilePicture: "",
 socket: {
 // 连接状态
 isConnected: false,
 // 消息内容
 message: '',
 // 重新连接错误
 reconnectError: false
 }
 },
 mutations: {
 SOCKET_ONOPEN (state, event) {
 // 连接打开触发的函数
 Vue.prototype.$socket = event.currentTarget;
 state.socket.isConnected = true
 },
 SOCKET_ONCLOSE (state, event) {
 // 连接关闭触发的函数
 state.socket.isConnected = false;
 console.log(event);
 },
 SOCKET_ONERROR (state, event) {
 // 连接发生错误触发的函数
 console.error(state, event)
 },
 SOCKET_ONMESSAGE (state, message) {
 // 收到消息时触发的函数
 state.socket.message = message
 },
 SOCKET_RECONNECT(state, count) {
 // 重新连接触发的函数
 console.info(state, count)
 },
 SOCKET_RECONNECT_ERROR(state) {
 // 重新连接失败触发的函数
 state.socket.reconnectError = true;
 },
 },
 actions: {
 customerAdded (context) {
 // 新连接添加函数
 console.log('action received: customerAdded');
 console.log(context)
 }
 },
 modules: {
 }
})

至此 vue-native-websocket 配置结束,如需了解更多配置方法,请移步 npm仓库

使用插件并实现群聊

在消息发送接收组件中添加 onmessage 监听(mounted生命周期中)

// 监听消息接收
this.$options.sockets.onmessage = (res)=>{
 // res.data为服务端返回的数据
 const data = JSON.parse(res.data);
 // 200为服务端连接建立成功时返回的状态码(此处根据真实后端返回值进行相应的修改)
 if(data.code===200){
 // 连接建立成功
 console.log(data.msg);
 }else{
 // 获取服务端推送的消息
 const msgObj = {
 msg: data.msg,
 avatarSrc: data.avatarSrc,
 userID: data.userID
 };
 // 渲染页面:如果msgArray存在则转json
 if(lodash.isEmpty(localStorage.getItem("msgArray"))){
 this.renderPage([],msgObj,0);
 }else{
 this.renderPage(JSON.parse(localStorage.getItem("msgArray")),msgObj,0);
 }
 }
};

实现消息发送

// 消息发送函数
sendMessage: function (event) {
 if (event.keyCode === 13) {
 // 阻止编辑框默认生成div事件
 event.preventDefault();
 let msgText = "";
 // 获取输入框下的所有子元素
 let allNodes = event.target.childNodes;
 for(let item of allNodes){
 // 判断当前元素是否为img元素
 if(item.nodeName==="IMG"){
 msgText += `/${item.alt}/`;
 }
 else{
 // 获取text节点的值
 if(item.nodeValue!==null){
 msgText += item.nodeValue;
 }
 }
 }
 // 消息发送: 消息内容、状态码、当前登录用户的头像地址、用户id
 this.$socket.sendObj({msg: msgText,code: 0,avatarSrc: this.$store.state.profilePicture,userID: this.$store.state.userID});
 // 清空输入框中的内容
 event.target.innerHTML = "";
 }
}

实现页面渲染

// 渲染页面函数
renderPage: function(msgArray,msgObj,status){
 if(status===1){
 // 页面第一次加载,如果本地存储中有数据则渲染至页面
 let msgArray = [];
 if(localStorage.getItem("msgArray")!==null){
 msgArray = JSON.parse(localStorage.getItem("msgArray"));
 for (let i = 0; i<msgArray.length;i++){
 const thisSenderMessageObj = {
 "msgText": msgArray[i].msg,
 "msgId": i,
 "avatarSrc": msgArray[i].avatarSrc,
 "userID": msgArray[i].userID
 };
 // 解析并渲染
 this.messageParsing(thisSenderMessageObj);
 }
 }
 }else{
 // 判断本地存储中是否有数据
 if(localStorage.getItem("msgArray")===null){
 // 新增记录
 msgArray.push(msgObj);
 localStorage.setItem("msgArray",JSON.stringify(msgArray));
 for (let i = 0; i <msgArray.length; i++){
 const thisSenderMessageObj = {
 "msgText": msgArray[i].msg,
 "msgId": i,
 "avatarSrc": msgArray[i].avatarSrc,
 "userID": msgArray[i].userID,
 };
 // 解析并渲染
 this.messageParsing(thisSenderMessageObj);
 }
 }else{
 // 更新记录
 msgArray = JSON.parse(localStorage.getItem("msgArray"));
 msgArray.push(msgObj);
 localStorage.setItem("msgArray",JSON.stringify(msgArray));
 const thisSenderMessageObj = {
 "msgText": msgObj.msg,
 "msgId": Date.now(),
 "avatarSrc": msgObj.avatarSrc,
 "userID": msgObj.userID
 };
 // 解析并渲染
 this.messageParsing(thisSenderMessageObj);
 }
 }
}

实现消息解析

// 消息解析
messageParsing: function(msgObj){
 // 解析接口返回的数据进行渲染
 let separateReg = /(\/[^/]+\/)/g;
 let msgText = msgObj.msgText;
 let finalMsgText = "";
 // 将符合条件的字符串放到数组里
 const resultArray = msgText.match(separateReg);
 if(resultArray!==null){
 for (let item of resultArray){
 // 删除字符串中的/符号
 item = item.replace(/\//g,"");
 for (let emojiItem of this.emojiList){
 // 判断捕获到的字符串与配置文件中的字符串是否相同
 if(emojiItem.info === item){
 const imgSrc = require(`../assets/img/emoji/${emojiItem.hover}`);
 const imgTag = `<img src="${imgSrc}" width="28" height="28" alt="${item}">`;
 // 替换匹配的字符串为img标签:全局替换
 msgText = msgText.replace(new RegExp(`/${item}/`,'g'),imgTag);
 }
 }
 }
 finalMsgText = msgText;
 }else{
 finalMsgText = msgText;
 }
 msgObj.msgText = finalMsgText;
 // 渲染页面
 this.senderMessageList.push(msgObj);
 // 修改滚动条位置
 this.$nextTick(function () {
 this.$refs.messagesContainer.scrollTop = this.$refs.messagesContainer.scrollHeight;
 });
}

DOM结构

通过每条消息的userID和vuex中的存储的当前用户的userID来判断当前消息是否为对方发送

<!--消息显示-->
<div class="messages-panel" ref="messagesContainer">
 <div class="row-panel" v-for="item in senderMessageList" :key="item.msgId">
 <!--发送者消息样式-->
 <div class="sender-panel" v-if="item.userID===userID">
 <!--消息-->
 <div class="msg-body">
 <!--消息尾巴-->
 <div class="tail-panel">
 <svg class="icon" aria-hidden="true">
 <use xlink:href="#icon-zbds30duihuakuangyou" rel="external nofollow" ></use>
 </svg>
 </div>
 <!--消息内容-->
 <p v-html="item.msgText"/>
 </div>
 <!--头像-->
 <div class="avatar-panel">
 <img :src="item.avatarSrc" alt="">
 </div>
 </div>
 <!--对方消息样式-->
 <div class="otherSide-panel" v-else>
 <!--头像-->
 <div class="avatar-panel">
 <img :src="item.avatarSrc" alt="">
 </div>
 <!--消息-->
 <div class="msg-body">
 <!--消息尾巴-->
 <div class="tail-panel">
 <svg class="icon" aria-hidden="true">
 <use xlink:href="#icon-zbds30duihuakuangzuo" rel="external nofollow" ></use>
 </svg>
 </div>
 <!--消息内容-->
 <p v-html="item.msgText"/>
 </div>
 </div>
 </div>
</div>

总结

以上所述是小编给大家介绍的Vue通过配置WebSocket并实现群聊功能,希望对大家有所帮助!

Javascript 相关文章推荐
jQuery 注意事项 与原因分析
Apr 24 Javascript
Javascript查询DBpedia小应用实例学习
Mar 07 Javascript
jQuery如何取id有.的值一般的方法是取不到的
Apr 18 Javascript
全面解析Bootstrap图片轮播效果
Dec 03 Javascript
基于Bootstrap仿淘宝分页控件实现代码
Nov 07 Javascript
bootstrap手风琴折叠示例代码分享
May 22 Javascript
解决AjaxFileupload 上传时会出现连接重置的问题
Jul 07 Javascript
使用webpack搭建react开发环境的方法
May 15 Javascript
element-ui表格数据转换的示例代码
Aug 24 Javascript
详解vue项目打包步骤
Mar 29 Javascript
vue实现todolist功能、todolist组件拆分及todolist的删除功能
Apr 11 Javascript
使用 JavaScript 制作页面效果
Apr 21 Javascript
Vue实现剪贴板复制功能
Dec 31 #Javascript
Vue+Element实现网页版个人简历系统(推荐)
Dec 31 #Javascript
小程序外卖订单界面的示例代码
Dec 30 #Javascript
记录微信小程序 height: calc(xx - xx);无效问题
Dec 30 #Javascript
JS三级联动代码格式实例详解
Dec 30 #Javascript
JavaScript监听触摸事件代码实例
Dec 30 #Javascript
微信公众号服务器验证Token步骤图解
Dec 30 #Javascript
You might like
thinkphp 多表 事务详解
2013/06/17 PHP
php生成数字字母的验证码图片
2015/07/14 PHP
php使用timthumb生成缩略图的方法
2016/01/22 PHP
Symfony核心类概述
2016/03/17 PHP
详解Yii2.0 rules验证规则集合
2017/03/21 PHP
基于jQuery实现的百度导航li拖放排列效果,即时更新数据库
2012/07/31 Javascript
javascript错误的认识不用关心内存管理
2012/12/15 Javascript
javascript移动设备Web开发中对touch事件的封装实例
2014/06/05 Javascript
iScroll中事件点击触发两次解决方案
2015/03/11 Javascript
json对象与数组以及转换成js对象的简单实现方法
2016/06/24 Javascript
微信公众平台开发教程(四) 实例入门:机器人回复(附源码)
2016/12/02 Javascript
利用js+css+html实现固定table的列头不动
2016/12/08 Javascript
基于bootstrop常用类总结(推荐)
2017/09/11 Javascript
浅谈vue项目重构技术要点和总结
2018/01/23 Javascript
去掉vue 中的代码规范检测两种方法(Eslint验证)
2018/03/21 Javascript
JavaScript设计模式之代理模式简单实例教程
2018/07/03 Javascript
傻瓜式解读koa中间件处理模块koa-compose的使用
2018/10/30 Javascript
python3 发送任意文件邮件的实例
2018/01/23 Python
Python日志模块logging基本用法分析
2018/08/23 Python
Python subprocess库的使用详解
2018/10/26 Python
python利用插值法对折线进行平滑曲线处理
2018/12/25 Python
Python英文文本分词(无空格)模块wordninja的使用实例
2019/02/20 Python
在python3.64中安装pyinstaller库的方法步骤
2020/06/02 Python
HTML5 语义化结构化规范化
2008/10/17 HTML / CSS
会走动的图形html5时钟示例
2014/04/27 HTML / CSS
80年代复古T恤:TruffleShuffle
2018/07/02 全球购物
地理科学专业毕业生求职信
2013/10/15 职场文书
市场营销专科应届生求职信
2013/11/24 职场文书
农业资源与环境专业自荐信范文
2013/12/30 职场文书
大学生职业生涯规划书汇总
2014/03/20 职场文书
教师爱岗敬业演讲稿
2014/05/05 职场文书
公司人事专员岗位职责
2014/08/11 职场文书
群众路线党员个人剖析材料
2014/10/08 职场文书
2014年基层党支部工作总结
2014/12/04 职场文书
Go语言特点及基本数据类型使用详解
2022/03/21 Golang
python manim实现排序算法动画示例
2022/08/14 Python