前言
前几篇我们讲了如何创建聊天室,一对一/一对多聊天,以及加已读未读消息状态。
这篇主要讲如何创建群聊和加入群聊。
还是跟之前一样,本文只写新加入的逻辑,之前逻辑请查看之前文章。
PS:效果稍微有点粗糙哈哈,不要在意这些细节~

先看效果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
大概思路:
通过传不同类型的type,区分是创建群还是添加群。
1、如果是10,创建群聊,我们就将群名称,以及生成的群id,存入groups里面,并且把创建群聊的人默认加入到群
2、如果是20,加入群聊,我们根据要加入的群id,找到对应的群,并把需要加入的人,加入到群
3、发送消息,判断是否有群id,如果没有表示一对一,逻辑不变。如果有群id,则去groups里面找到对应的群,并拿出群下面所有的user,根据id,找到对应的conn(用户连接),发送消息。

流程图:

创建群:
在这里插入图片描述
加入群:

在这里插入图片描述
上代码:

服务端:
(…表示跟之前逻辑一致,不在多写)

...
收到客户端数据处理:
(主要是增加了type为1020, 12只是新增了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框架组件,无自定义样式。

参考链接:Node + WebSocket + Vue 聊天室创建群聊/加入群聊功能 – 第五章

Logo

前往低代码交流专区

更多推荐