前言
前几篇我们讲了如何创建聊天室,一对一/一对多聊天,以及加已读未读消息状态。
这篇主要讲如何创建群聊和加入群聊。
还是跟之前一样,本文只写新加入的逻辑,之前逻辑请查看之前文章。
PS:效果稍微有点粗糙哈哈,不要在意这些细节~
先看效果:
大概思路:
通过传不同类型的type,区分是创建群还是添加群。
1、如果是10,创建群聊,我们就将群名称,以及生成的群id,存入groups里面,并且把创建群聊的人默认加入到群
2、如果是20,加入群聊,我们根据要加入的群id,找到对应的群,并把需要加入的人,加入到群
3、发送消息,判断是否有群id,如果没有表示一对一,逻辑不变。如果有群id,则去groups里面找到对应的群,并拿出群下面所有的user,根据id,找到对应的conn(用户连接),发送消息。
流程图:
创建群:
加入群:
上代码:
服务端:
(…表示跟之前逻辑一致,不在多写)
...
收到客户端数据处理:
(主要是增加了type为10和20, 1和2只是新增了groups字段,gorups需全局定义)
switch (obj.type) {
case 1:
{
// 将所有uid对应的连接都保存到一个对象里
conns[obj.uid] = conn;
// 不存在uid对应的用户(不是本人),才会添加,避免重复
const isSelf = users.some(m => m.uid === obj.uid)
console.log(isSelf, data.uid, users, '所有用户')
if (!isSelf) {
users.push({
nickname: obj.nickname,
uid: obj.uid
})
}
broadcast({
type: 1,
nickname: obj.nickname,
uid: obj.uid,
msg: `${obj.nickname}进入了聊天室`,
date: moment().format('YYYY-MM-DD HH:mm:ss'),
users,
brige: obj.brige,
groups
})
}
break;
case 2:
broadcast({
type: 2,
nickname: obj.nickname,
uid: obj.uid,
msg: obj.msg,
users,
date: moment().format('YYYY-MM-DD HH:mm:ss'),
brige: obj.brige,
status: 1, // 表示未读
groups,
groupId: obj.groupId
})
break;
case 10:
groups.push({
id: moment().valueOf(),
name: obj.name,
users: [{
nickname: obj.nickname,
uid: obj.uid
}]
})
broadcast({
type: 1,
nickname: obj.nickname,
uid: obj.uid,
date: moment().format('YYYY-MM-DD HH:mm:ss'),
msg: `${obj.nickname}创建了${obj.name}群`,
brige: obj.brige,
users,
groups
})
break;
case 20:
// 找到当前群,往当前群的userspush进去登录人信息
currentGroup = groups.filter(item => { return item.id === obj.groupId })[0]
currentGroup.users.push({
uid: obj.uid,
nickname: obj.nickname
})
broadcast({
type: 1,
nickname: obj.nickname,
uid: obj.uid,
date: moment().format('YYYY-MM-DD HH:mm:ss'),
msg: `${obj.nickname}加入了${obj.groupName}群`,
brige: obj.brige,
users,
groups,
groupId: obj.groupId // 有是群聊,没有是单聊
})
break;
}
function broadcast(obj) {
... (跟之前逻辑一致,以下为新增:)
// 如果是有groupId代表是群消息
if (obj.groupId) {
// 找到对应群
currentGroup = groups.filter(item=>{
return item.id === obj.groupId
})[0];
// 变量群里面的任意,发送消息
currentGroup.users.forEach(item=>{
conns[item.uid].sendText(JSON.stringify(obj));
})
return;
}
}
客户端
视图层:
// 这个dialog可自己写,此处只做参考。(新建群模态框)
<el-dialog
:visible="showGroupDialog"
>
<el-input type="text" v-model="groupName" placeholder="请输入群名称" ></el-input>
<span slot="footer" class="dialog-footer">
<el-button @click="showGroupDialog = false">取 消</el-button>
<el-button type="primary" @click="createGroup">确 定</el-button>
</span>
</el-dialog>
// 这块主要是群展示做了更改,之前是默认写死了个群,现在是数组遍历得到。
<div class="left">
<p class="user" @click="showGroupDialog = true">新建群</p>
<div class="user" v-for="items in groups" :key="items.id" @click="triggerGroup(items)">
<span> {{items.name}}</span>
<span v-if="!isUserInGroup(items)" @click="addGroup(items.id)">+</span>
<span class="msgtip" v-show="getGroupMsgNum(items)">{{getGroupMsgNum(items)}}</span>
</div>
<div class="user" v-for="(itm, idex) in users" :key="idex" v-show="itm.uid !== uid" @click="triggerUser(itm)">
<span>{{itm.nickname}}</span>
<span class="msgtip" v-show="getMsgNum(itm)">{{getMsgNum(itm)}}</span>
</div>
</div>
逻辑层:
export default {
data () {
return {
...
groups: [], // 所有群对应数组
showGroupDialog: false, // 新建群模态框
groupName: '', // 群名
groupId: ''
}
}
computed: {
// 筛选当前brige一致的放到一个聊天数组里,区分单聊和群聊
currentMessage () {
const vm = this
let data = this.messageList.filter(item => {
// 如果有groupId,过滤展示出当前对应群
if (this.groupId) {
return item.groups.filter(p => { return p.id === this.groupId })
} else {
return item.brige.sort().join('') === vm.brige.sort().join('')
}
})
data.forEach(m => {
m.status = 0
})
return data
}
},
methods: {
// 发送信息给客户端
sendMessage (type, msg) {
const data = {
...
groups: this.groups,
groupId: this.groupId
}
this.ws.send(JSON.stringify(data))
this.msg = ''
},
// 创建群
createGroup () {
const data = {
uid: this.uid,
type: 10,
nickname: this.nickname,
users: this.users,
name: this.groupName,
brige: []
}
this.ws.send(JSON.stringify(data))
this.showGroupDialog = false
this.groupName = ''
},
// 加入群
addGroup (id) {
const data = {
uid: this.uid,
type: 20,
nickname: this.nickname,
brige: [],
groupName: this.groupName,
groupId: id
}
this.ws.send(JSON.stringify(data))
},
// 判断当前用户是否在群里
isUserInGroup (items) {
const isIn = items.users.some(item => { return item.uid === this.uid })
return isIn
},
// 获取单聊消息未读数量
getMsgNum (user) {
// userid相同,确认是当前聊天对应人的消息数组
return this.messageList.filter (m => {
return m.brige.length && m.status === 1 && m.uid === user.uid
}).length
},
// 获取群聊未读消息数
getGroupMsgNum (users) {
return this.messageList.filter (m => {
return m.groupId === users.id && m.status === 1
}).length
},
triggerUser (itm) {
this.brige = [this.uid, itm.uid]
this.title = `和${itm.nickname}聊天`
},
triggerGroup (items) {
const isIn = items.users.some(item => { return item.uid === this.uid})
if (!isIn) {
this.$message.error('您还不是该群成员,不可发信息!');
return;
}
this.groupId = items.id
this.brige = []
this.title = `在${items.name}聊天`
},
// 连接websocket
contactSocket () {
...
ws.onmessage = function (e) {
const obj = JSON.parse(e.data)
that.messageList.push(obj)
if (obj.users) that.users = obj.users
if (obj.groups) that.groups = obj.groups
}
}
}
样式层:
使用elementui框架组件,无自定义样式。