vue+websokect实现实时聊天,可单聊、可群聊

花生 可爱的博主

时间: 2024-10-27 阅读: 2 字数:7318

{}
一个实时聊天的功能,其核心就是websokect,进行双向平等对话,从后端主动推送消息到前端,实现实时推送消息的功能。

目录

效果图

效果图

效果网站链接(仅供学习交流)

效果小程序二维码

(需在Web端获取账号) 二维码1 二维码2 二维码3

思路

实时聊天功能

我们要实现一个实时聊天功能,包括单聊和群聊,避免无差别的广播,需支持向指定用户发送消息。

还需要区分在线和离线状态,因此聊天信息必须存储到MySQL数据库,这样即使用户离线,重新上线时也能收到未读消息。

第一步

实时聊天的核心是WebSocket,它支持双向通信,后端可以主动向前端推送消息。关于WebSocket的具体介绍,可以查看以下链接:

第二步

接下来,编写后端核心代码,这里使用Node.js的Express框架。

如果想用Java作为后端,可以参考这个帖子:Springboot实现WebSocket

代码解析:conn是用户连接信息,用户连接到WebSocket时,会将其ID发送给后端并以ID作为key存储连接信息,以实现单聊或指定群聊功能,broadcast()则用于发送指定用户的消息。

let conns2 = {}; // 实时聊天用户连接属性集

// websocket 实时聊天
const wss2 = new WebSocket.Server({ port: 8082 });
wss2.on('connection', function connection(ws, req) {
  // 获取用户ID
  let index = req.url.indexOf('=');
  let id = req.url.substr(index + 1, req.url.length);
  console.log('成功连接实时聊天, 用户: ' + id);
  conns2[id] = ws; // 存储用户连接信息

  ws.on('message', function incoming(message) {
    const obj = JSON.parse(message);
    broadcast(obj); // 广播消息
  });

  ws.on('close', function(e) {
    console.log(e, '服务端连接关闭');
  });

  ws.on('error', function(e) {
    console.log(e, '服务端异常');
  });
});

broadcast函数中,我们判断消息的类型,确认是单聊还是群聊,并将消息发送给在线的用户。

// 实时聊天发送消息处理
function broadcast(obj) {
  let users = [];

  if (obj.type === '1') { // 单聊
    users.push(obj.send_id);
    users.push(obj.accept_id);
  } else if (obj.type === '2') { // 群聊
    users = obj.accept_group;
  }

  if (users && users.length) {
    users.forEach(item => {
      if (typeof conns2[item] === 'undefined') {
        console.log(item + '---该用户已离线');
      } else {
        conns2[item].send(JSON.stringify(obj)); // 发送消息
      }
    });
  }
}

第三步

接下来,编写前端样式,这里使用Vue框架。

<template>
  <div class="mess">
    <div class="mess_user_list">
      <div class="user">
        <el-avatar :size="40" :src="userAvatar" style="margin: 5px;"></el-avatar>
        {{userName}}
      </div>
      <div class="user_list">
        <div v-for="(item, index) in userList" :key="index" @click="showmessdlog(item)" class="user_list_item">
          <el-avatar :size="40" :src="userAvatar" style="margin: 5px;"></el-avatar>
          <div>
            {{item.name}}
            [{{messlst[item.id][messlst[item.id].length-1].send_name}}] {{messlst[item.id][messlst[item.id].length-1].content}}
            暂无消息
          </div>
        </div>
      </div>
    </div>
    <div v-if="acceptUser !== ''" class="mess_dialog">
      <div class="dlog_header">{{acceptUser}}</div>
      <div class="dlog_content">
        <div v-for="(item, index) in messnowList" :key="index" class="dlog_content_item" style="margin-left: 5px;">
          <div v-if="item.send_id !== userId" class="content_other">
            {{item.send_name}} {{item.send_date}}
            {{item.content}}
          </div>
          <div v-else class="content_me">
            {{item.send_date}} {{item.send_name}}
            {{item.content}}
          </div>
        </div>
      </div>
      <div class="dlog_footer">
        <el-input type="textarea" :rows="5" v-model="mess"></el-input>
        <el-button type="primary" @click="Wssendmess" style="float: right; margin-top: 5px;">发送</el-button>
      </div>
    </div>
    <div v-else class="mess_dialog_false">
      暂无消息,请选择用户对象
    </div>
  </div>
</template>

CSS样式如下:

<style scoped>
.mess {
  border-radius: 5px;
  margin: 20px auto;
  width: 950px;
  height: 600px;
  border: 1px #8a8282;
  box-shadow: 0 0 10px #9b9393;
  background-color: white;
  display: flex;
}

.mess_user_list {
  width: 270px;
  height: 100%;
  background-color: #9f9c9c;
}

.mess_dialog {
  width: 680px;
  height: 600px;
}

.mess_dialog_false {
  width: 680px;
  height: 600px;
  text-align: center;
  line-height: 600px;
}

.dlog_header, .user {
  height: 60px;
  display: flex;
  align-items: center;
  border-bottom: 1px solid #0a0a0a;
}

.user_list {
  height: 540px;
  overflow-y: scroll;
}

.user_list_item {
  height: 60px;
  background-color: #b3b3b4;
  display: flex;
  align-items: center;
}

.content_other {
  width: 650px;
}

.content_me {
  width: 650px;
  text-align: right;
}
</style>

第四步

最后,编写前端JavaScript代码,连接后端WebSocket并监听状态变化,绑定事件处理:

const ws = new WebSocket('ws://localhost:8082?id=' + id);

mounted() {
  ws.addEventListener('open', this.handleWsOpen.bind(this), false);
  ws.addEventListener('close', this.handleWsClose.bind(this), false);
  ws.addEventListener('error', this.handleWsError.bind(this), false);
  ws.addEventListener('message', this.handleWsMessage.bind(this), false);
},
methods: {
  handleWsOpen() {
    console.log('WebSocket已打开');
  },
  handleWsClose(e) {
    console.log('WebSocket连接关闭:', e);
  },
  handleWsError(e) {
    console.log('WebSocket发生错误:', e);
  },
  handleWsMessage(e) {
    console.log('WebSocket收到消息:', e.data);
  }
}

连接成功后,前端可以使用ws.send()发送消息给后端,同时存储在MySQL中,后端会处理后按需给对应的前端发送消息。

原文地址:CSDN博客

本文章网址:https://www.sjxi.cn/detil/905489af7043462a807bab9dae8eea7c
最新评论
当前未登陆哦
登陆后才可评论哦

湘ICP备2021009447号

×

(穷逼博主)在线接单

QQ: 1164453243

邮箱: abcdsjx@126.com

前端项目代做
前后端分离
Python 爬虫脚本
Java 后台开发
各种脚本编写
服务器搭建
个人博客搭建
Web 应用开发
Chrome 插件编写
Bug 修复