Node + WebSocket + Vue 聊天室建立群聊/加入群聊

suliver發表於2021-09-09

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

前言

圖片描述

本次算是做了一個小小的專題吧,“Nodejs + WebSocket + Vue實現聊天室功能”,目前還在一步一步推進,之前已經可以一對一、一對多聊天了,今天就來建立群聊組,加入群聊組等,同時專案中加入了全域性message提示框,有興趣的可以去看看。

如果您還沒有看過之前的文字,請點選下方連結檢視!
推薦文章:




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、同時頁面校驗等做了一些處理,判斷使用者是否在群裡面,不在不能傳送訊息;發訊息前需選擇使用者或者群;

快速預覽效果

圖片描述

圖片描述

圖片描述

圖片描述

圖片描述

原始碼地址:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2370/viewspace-2822827/,如需轉載,請註明出處,否則將追究法律責任。

相關文章