前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Nodejs + WebSocket + Vue 一对一、一对多聊天室 – 第三章

Nodejs + WebSocket + Vue 一对一、一对多聊天室 – 第三章

作者头像
Javanx
发布2019-09-04 11:19:39
2.1K0
发布2019-09-04 11:19:39
举报
文章被收录于专栏:web秀web秀

前言

Nodejs + WebSocket + Vue 一对一、一对多聊天室 - 第三章
Nodejs + WebSocket + Vue 一对一、一对多聊天室 - 第三章

如果你看到这篇文章,还没有了解前面2篇文章的同学,可以先去了解一波,这样上手更快。 推荐文章:

《Nodejs + WebSocket简单介绍及示例 - 第一章》 《Nodejs + WebSocket + Vue 实现多人聊天室WebIM功能 - 第二章》

这篇文章都是前面文章的加强版,功能升级。给大家提供一个循序渐进的学习过程,一步一步的来。

在第二篇文章结束时,我们就已经可以一对多的聊天了,就是多人群聊。这次,我们进行扩展来实现一对一、一对多功能。

WebSocket客户端UI界面更改

有了一对一,一对多,我们就需要对直接的界面做出调整了。左边显示聊天人员列表,右边是具体消息列表。

Nodejs + WebSocket + Vue 一对一、一对多聊天室 - 第三章
Nodejs + WebSocket + Vue 一对一、一对多聊天室 - 第三章
代码语言:javascript
复制
<div class="web-im">
  <div class="dis-flex">
    <div class="user-list">
      <div class="user" @click="triggerGroup">群1</div>
      <div class="user" @click="triggerPersonal(item)" v-if="item.uid!=uid" v-for="item in users">{{item.nickname}}</div>
    </div>
    <div class="msg-content">
      <div class="header im-title">{{title}}</div>
        <div class="content im-record">
          <div class="li" :class="{user: item.uid == uid}" v-for="item in currentMessage">
            <template v-if="item.type===1">
              <p class="join-tips">{{item.msg}}</p>
            </template>
            <template v-else>
              <div class="img">{{item.nickname}}</div>
              <p class="message-box">{{item.msg}}</p>
            </template>
          </div>
        </div>
        <div class="footer im-input">
          <input type="text" v-model="msg" placeholder="请输入内容">
          <button @click="send">发送</button>
        </div>
    </div>
  </div>
</div>
...

这里我们就写死了一个群,叫群1,默认是所用用户进去群聊。

WebSocket服务端

代码语言:javascript
复制
var ws = require("nodejs-websocket");
var moment = require('moment');

console.log("开始建立连接...")

let users = [];
let conns = {};

function boardcast(obj) {
  // bridge用来实现一对一的主要参数
  if(obj.bridge && obj.bridge.length){
    obj.bridge.forEach(item=>{
      conns[item].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);
    // 将所有uid对应的连接conn存到一个对象里面
    conns[''+obj.uid+''] = conn;
    if(obj.type===1){
      let isuser = users.some(item=>{
        return item.uid === obj.uid
      })
      if(!isuser){
        users.push({
          nickname: obj.nickname,
          uid: obj.uid
        });
      }
      boardcast({
        type: 1,
        date: moment().format('YYYY-MM-DD HH:mm:ss'),
        msg: obj.nickname+'加入聊天室',
        users: users,
        uid: obj.uid,
        nickname: obj.nickname,
        // 增加参数
        bridge: obj.bridge
      });
    } else {
      boardcast({
        type: 2,
        date: moment().format('YYYY-MM-DD HH:mm:ss'),
        msg: obj.msg,
        uid: obj.uid,
        nickname: obj.nickname,
        // 增加参数
        bridge: obj.bridge
      });
    }
  })
  conn.on("close", function (code, reason) {
    console.log("关闭连接")
  });
  conn.on("error", function (code, reason) {
    console.log("异常关闭")
  });
}).listen(8001)
console.log("WebSocket建立完毕")

主体结构还是和第二章类型,不同的是: 1、每次将uid对应的conn存储到一个对象conns上 2、根据客户端传入的参数bridge来判断,是群发还是一对一发送 3、群发还是第二章逻辑即可

代码语言:javascript
复制
server.connections.forEach((conn, index) => {
  conn.sendText(JSON.stringify(obj));
})

4、一对一发送,bridge里面是一对一的两个用户uid,这样就可以在conns对象上找到uid对应的连接conn,并用conn发送信息即可

代码语言:javascript
复制
if(obj.bridge && obj.bridge.length){
  obj.bridge.forEach(item=>{
    conns[item].sendText(JSON.stringify(obj));
  })
  return;
}

WebSocket客户端

代码语言:javascript
复制
export default {
  ...
  data(){
    return {
      title: '群聊',
      uid: '',
      nickname: '',
      socket: '',
      msg: '',
      // 当前用户所有消息
      messageList: [],
      users: [],
      bridge: []
    }
  },
  mounted() {
    ...
  },
  computed: {
    // 当前对话渲染的msg列表
    currentMessage() {
      let vm = this;
      // 筛选只有bridge相同的对话,展示出来
      // 数组比较,先转成字符串
      let data = vm.messageList.filter(item=>{
        return item.bridge.sort().join(',') == vm.bridge.sort().join(',')
      })
      return data;
    }
  },
  methods: {
    // 切换到群聊
    triggerGroup() {
      this.bridge = [];
      this.title = '群聊';
    },
    // 切到具体个人
    triggerPersonal(item) {
      if(this.uid === item.uid){
        return;
      }
      // 将当前用户uid,和需要对话的uid放入bridge
      this.bridge = [this.uid, item.uid];
      this.title = '和' + item.nickname + '聊天';
    },
    send(){
      if(!this.msg){
        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参数
        bridge: this.bridge
      }));
      this.msg = '';
    },
    conWebSocket(){
      let vm = this;
      if(window.WebSocket){
        vm.socket = new WebSocket('ws://localhost:8001');
        let socket = vm.socket;

        socket.onopen = function(e){
          console.log("连接服务器成功");
          if(!vm.uid){
            ...
          }
          // 这里将sendMessage方法if外面
          vm.sendMessage(1)
        }
        socket.onclose = function(e){
          console.log("服务器关闭");
        }
        socket.onerror = function(){
          console.log("连接出错");
        }
        // 接收服务器的消息
        socket.onmessage = function(e){
          let message = JSON.parse(e.data);
          vm.messageList.push(message);
          if(message.users) {
            vm.users = message.users;
          }
        }   
      }
    },
    login(){
      ...
    }
  }
}

上方...的代码区域都是和第二篇文章一样的地方,所有就省略了。

1、默认是群发,即bridge是空数组,向所有用户发送消息 2、点击用户列表,赋予bridge当前用户uid,和需要对话的uid。 3、在第二篇文章中,渲染的消息列表是messageList。现在不是,是通过计算属性computed,只需要bridge相等的消息,得出currentMessage当前对话的消息列表 4、因为所有消息都是通过后台socket返回,也不需要考虑发送者/接收者是谁,判断bridge是否相等,可以用sort()方法排序并转换成字符串后进行对比。

快速预览效果

Nodejs + WebSocket + Vue 一对一、一对多聊天室 - 第三章
Nodejs + WebSocket + Vue 一对一、一对多聊天室 - 第三章
Nodejs + WebSocket + Vue 一对一、一对多聊天室 - 第三章
Nodejs + WebSocket + Vue 一对一、一对多聊天室 - 第三章
Nodejs + WebSocket + Vue 一对一、一对多聊天室 - 第三章
Nodejs + WebSocket + Vue 一对一、一对多聊天室 - 第三章

总结

一对一和一对多的核心,就是知道是那个用户与那个用户对话。当前目前一对多是不用考虑,因为是写死的,所有用户,后面来做不同群,随意加群聊天,就需要考虑了。也就是服务端的conn不要弄错,不然收不到消息也接收不到消息。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年4月29日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • WebSocket客户端UI界面更改
  • WebSocket服务端
  • WebSocket客户端
  • 快速预览效果
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档