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中全局函数each使用介绍
Dec 10 Javascript
JS如何实现文本框随文本的长度而增长
Jul 30 Javascript
jQuery右侧选项卡焦点图片轮播特效代码分享
Sep 05 Javascript
Javascript生成全局唯一标识符(GUID,UUID)的方法
Feb 27 Javascript
详解vue移动端项目的适配(以mint-ui为例)
Aug 17 Javascript
Vue中使用sass实现换肤功能
Sep 07 Javascript
react native基于FlatList下拉刷新上拉加载实现代码示例
Sep 30 Javascript
小程序二次贝塞尔曲线实现购物车商品曲线飞入效果
Jan 07 Javascript
详解如何模拟实现node中的Events模块(通俗易懂版)
Apr 15 Javascript
js实现简单掷骰子效果
Oct 24 Javascript
VUE渲染后端返回含有script标签的html字符串示例
Oct 28 Javascript
在vue中把含有html标签转为html渲染页面的实例
Oct 28 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
php excel类 phpExcel使用方法介绍
2010/08/21 PHP
PHP中的函数嵌套层数限制分析
2011/06/13 PHP
PHP递归遍历指定目录的文件并统计文件数量的方法
2015/03/24 PHP
PHP数组操作――获取数组最后一个值的方法
2015/04/14 PHP
今天你说520了吗?不仅有php表白书还有java表白神器
2016/05/20 PHP
php版微信开发Token验证失败或请求URL超时问题的解决方法
2016/09/23 PHP
PHP输出多个元素的排列或组合的方法
2017/03/14 PHP
关于ThinkPhp 框架表单验证及ajax验证问题
2017/07/19 PHP
PhpStorm的使用教程(本地运行PHP+远程开发+快捷键)
2020/03/26 PHP
判断iframe是否加载完成的完美方法
2010/01/07 Javascript
修改jquery里的dialog对话框插件为框架页(iframe) 的方法
2010/09/14 Javascript
jQuery之DOM对象和jQuery对象的转换与区别分析
2015/01/08 Javascript
浅谈javascript中基本包装类型
2015/06/03 Javascript
深入探讨前端框架react
2015/12/09 Javascript
Jquery为DIV添加click事件的简单实例
2016/06/02 Javascript
JS产生随机数的几个用法详解
2016/06/22 Javascript
浅谈js原生拖放
2016/11/21 Javascript
原生js实现放大镜
2017/02/20 Javascript
angularjs实现多张图片上传并预览功能
2017/02/24 Javascript
Javascript之图片的延迟加载的实例详解
2017/07/24 Javascript
详解webpack-dev-server使用http-proxy解决跨域问题
2018/01/13 Javascript
微信小程序radio组件使用详解
2018/01/31 Javascript
vue.js项目 el-input 组件 监听回车键实现搜索功能示例
2018/08/25 Javascript
Postman环境变量全局变量使用方法详解
2020/08/13 Javascript
WebPack工具运行原理及入门教程
2020/12/02 Javascript
Python的多态性实例分析
2015/07/07 Python
详解Django通用视图中的函数包装
2015/07/21 Python
理解python正则表达式
2016/01/15 Python
Python Pandas找到缺失值的位置方法
2018/04/12 Python
使用Python实现跳帧截取视频帧
2019/05/31 Python
用Python抢火车票的简单小程序实现解析
2019/08/14 Python
新建文件时Pycharm中自动设置头部模板信息的方法
2020/04/17 Python
英国网上香水店:Fragrance Direct
2016/07/20 全球购物
台湾屈臣氏网路商店:Watsons台湾
2020/12/29 全球购物
实习推荐信格式模板
2015/03/27 职场文书
幼儿园新生开学寄语
2015/05/27 职场文书