前言

Node + WebSocket + Vue 聊天室创建群聊/加入群聊功能 - 第五章

本次算是做了一个小小的专题吧,“Nodejs + WebSocket + Vue实现聊天室功能”,目前还在一步一步推进,之前已经可以一对一、一对多聊天了,今天就来创建群聊组,加入群聊组等,同时项目中加入了全局message提示框,有兴趣的可以去看看。

如果您还没有看过之前的文字,请点击下方链接查看!
推荐文章:

《Nodejs + WebSocket简单介绍及示例 - 第一章》
《Nodejs + WebSocket + Vue 实现多人聊天室WebIM功能 - 第二章》
《Nodejs + WebSocket + Vue 一对一、一对多聊天室 - 第三章》
《Node + WebSocket + Vue 一对一、一对多聊天室消息已读未读 - 第四章》

WebSocket服务端

做出调整的地方有注释,后面也会做出讲解。

... let users = []; let conns = {}; // 群组数组,多个群 let groups = []; function boardcast(obj) { if(obj.bridge && obj.bridge.length){ obj.bridge.forEach(item=>{ conns[item].sendText(JSON.stringify(obj)); }) return; } // 如果是有groupId代表是群消息 if (obj.groupId) { // 找到对应群 group = groups.filter(item=>{ return item.id === obj.groupId })[0]; // 变量群里面的任意,发送消息 group.users.forEach(item=>{ conns[item.uid].sendText(JSON.stringify(obj)); }) return; } server.connections.forEach((conn, index) => { conn.sendText(JSON.stringify(obj)); }) } var server = ws.createServer(function(conn){ conn.on("text", function (obj) { obj = JSON.parse(obj); conns[''+obj.uid+''] = conn; // 由原来的if改成switch case switch(obj.type){ // 创建连接 case 1: ... break; // 创建群 case 10: // 向groups push数据,同时默认把创建者加入到该群 groups.push({ id: moment().valueOf(), name: obj.groupName, users: [{ uid: obj.uid, nickname: obj.nickname }] }) // 把创建的消息推送给所有用户 boardcast({ type: 1, date: moment().format('YYYY-MM-DD HH:mm:ss'), msg: obj.nickname+'创建了群' + obj.groupName, users: users, groups: groups, uid: obj.uid, nickname: obj.nickname, bridge: obj.bridge }); break; // 加入群 case 20: // 根据传入的groupId找到对应的群 let group = groups.filter(item=>{ return item.id === obj.groupId })[0] // 向对应的群成员users push数据 group.users.push({ uid: obj.uid, nickname: obj.nickname }) boardcast({ type: 1, date: moment().format('YYYY-MM-DD HH:mm:ss'), msg: obj.nickname+'加入了群' + obj.groupName, users: users, groups: groups, uid: obj.uid, nickname: obj.nickname, bridge: obj.bridge }); break; // 发送消息 default: boardcast({ type: 2, date: moment().format('YYYY-MM-DD HH:mm:ss'), msg: obj.msg, uid: obj.uid, nickname: obj.nickname, bridge: obj.bridge, // 添加groupId参数,有是群发,没有是一对一 groupId: obj.groupId, status: 1 }); break; } }) ... }).listen(8001) ...

ok, 通过上方的代码,以及注释,相信很多小伙伴应该都明白了,这里简单讲解一下。

根据前端页面传入的type,来判断是什么操作?

1、如果是10,创建群聊,我们就将群名称,以及生成的群id,存入groups里面,并且把创建群聊的人默认加入到群
2、如果是20,加入群聊,我们根据要加入的群id,找到对应的群,并把需要加入的人,加入到群
3、发送消息,判断是否有群id,如果没有表示一对一,逻辑不变。如果有群id,则去groups里面找到对应的群,并拿出群下面所有的user,根据id,找到对应的conn(用户连接),发送消息。

WebSocket客户端JS

我们也主要研究变的地方,没有变的通过…表示。同时,如果您想看完整代码,可以去文章最下方“了解更多”,来获取源码查看。

... export default { ... data(){ return { title: '请选择群或者人员进行聊天', ... groups: [], // 群组 groupId: '' // 当前群聊id } }, mounted() { ... // 不变 }, computed: { currentMessage() { let vm = this; let data = vm.messageList.filter(item=>{ if(this.groupId) { return item.groupId === this.groupId } else if(item.bridge.length){ return item.bridge.sort().join(',') == vm.bridge.sort().join(',') } }) data.map(item=>{ item.status = 0 return item; }) return data; } }, methods: { addGroup(item){ this.socket.send(JSON.stringify({ uid: this.uid, type: 20, nickname: this.nickname, groupId: item.id, groupName: item.name, bridge: [] })); this.$message({type: 'success', message: `成功加入${item.name}群`}) }, checkUserIsGroup (item) { return item.users.some(item=>{ return item.uid === this.uid }) }, createGroup(){ this.socket.send(JSON.stringify({ uid: this.uid, type: 10, nickname: this.nickname, groupName: this.groupName, bridge: [] })); }, getGroupMsgNum(group){ return this.messageList.filter(item=>{ return item.groupId === group.id && item.status === 1 }).length }, getUserMsgNum(user){ return this.messageList.filter(item=>{ return item.bridge.length && item.uid === user.uid && item.status === 1 }).length }, triggerGroup(item) { let issome = item.users.some(item=>{ return item.uid === this.uid }) if(!issome){ this.$message({type: 'error', message: `您还不是${item.name}群成员`}) return } this.bridge = []; this.groupId = item.id; this.title = `和${item.name}群成员聊天`; }, triggerPersonal(item) { if(this.uid === item.uid){ return; } this.groupId = ''; this.bridge = [this.uid, item.uid]; this.title = `和${item.nickname}聊天`; }, send(){ if(!this.msg){ return } if(!this.bridge.length && !this.groupId){ this.$message({type: 'error', message: '请选择发送人或者群'}) return; } this.sendMessage(2, this.msg) }, sendMessage(type, msg){ this.socket.send(JSON.stringify({ uid: this.uid, type: type, nickname: this.nickname, msg: msg, bridge: this.bridge, groupId: this.groupId // 如果群聊id,可能为空(一对一) })); this.msg = ''; }, conWebSocket(){ let vm = this; if(window.WebSocket){ vm.socket = new WebSocket('ws://localhost:8001'); let socket = vm.socket; ... // 接收服务器的消息 socket.onmessage = function(e){ let message = JSON.parse(e.data); vm.messageList.push(message); if(message.users) { vm.users = message.users; } if (message.groups){ vm.groups = message.groups; } } } }, login(){ ... } } }

WebSocket客户端HTML

... <div class="user-list"> <div class="user create-group-btn" @click="$refs.createGroupDialog.show()">新建群</div> <div class="user" @click="triggerGroup(item)" v-for="item in groups"> {{item.name}} <span class="tips-num">{{getGroupMsgNum(item)}}</span> <span v-if="!checkUserIsGroup(item)" @click.stop="addGroup(item)" class="add-group">+</span> </div> <div class="user" @click="triggerPersonal(item)" v-if="item.uid!=uid" v-for="item in users"> {{item.nickname}} <span class="tips-num">{{getUserMsgNum(item)}}</span> </div> </div> ...

这里增加了遍历groups群里,同时判断当前用户是否在群里里面,没有则有一个加入按钮。

解析客户端代码

1、socket.onmessage来判断是否有groups群组,有就赋值给groups
2、创建群组,输入名称,确认后,发送给服务端,告诉是创建群组,已经创建人员、群组名称等
3、加入群组,发送给服务端要加入群组id,当前用户id
4、获取群未读消息数量和之前类似,只需要判断,是群消息,并且status为1
5、同时页面校验等做了一些处理,判断用户是否在群里面,不在不能发送消息;发消息前需选择用户或者群;

快速预览效果

Node + WebSocket + Vue 聊天室创建群聊/加入群聊功能 - 第五章

Node + WebSocket + Vue 聊天室创建群聊/加入群聊功能 - 第五章

Node + WebSocket + Vue 聊天室创建群聊/加入群聊功能 - 第五章

Node + WebSocket + Vue 聊天室创建群聊/加入群聊功能 - 第五章

Node + WebSocket + Vue 聊天室创建群聊/加入群聊功能 - 第五章

源码地址:源码地址