欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-04-09 16:33:20
原文链接: 写jquery项目时,使用websocket很简单,不用去考虑模块化,组件之间的访问问题,面向文档编程即可,在vue项目中使用时,远远没有想象中的那么简单,需要考虑很多场...

原文链接:

写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并实现群聊功能,希望对大家有所帮助!