vue3+nodeJs+webSocket实现聊天功能

金歌  论坛元老 | 2025-4-14 08:26:30 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1693|帖子 1693|积分 5079

利用websocket 来实现聊天功能,紧张是通过以下几点来实现的
一、利用nodejs来实现后端接口
     1、起首举行初始化
        
  1.   const { WebSocketServer } = require("ws"); //  引入WebSocketServer模块
  2.   const Websocket = require("ws");
  3.   const WebSocket = require("ws"); //  引入WebSocket模块
  4.   const onLineList = []; //  定义一个在线用户列表
  5. // 我们的port是8090
  6.   const wss = new WebSocket.Server({ port: 8080 });
  7. // 如果有ws就代表初始化成功
  8.   if (wss) {
  9.     console.log("ws初始化成功");
复制代码
2、举行连接 --- 设置进入的欢迎语
  
  1. const user = new URL(request.url, `http://${request.headers.host}`).searchParams.get('user');
  2.     console.log(`${user} 已连接`);
  3.     let welCome = JSON.stringify({
  4.       type: "tips",
  5.       content: "欢迎加入聊天室,现在我们开始畅聊吧"
  6.     });
  7.     ws.send(welCome, { binary: false });
复制代码
 2)举行注册消息的变乱
      
  1. ws.on("message", async function message(data) {
  2.       const message = JSON.parse(data); //  将收到的数据解析为JSON格式
  3.       switch (
  4.         message.type //  根据消息类型进行不同的处理
  5.         ) {
  6.         case "init":
  7.           if (message.userId) {
  8.             //  如果消息中包含用户id
  9.             // 为当前的用户  ws链接绑定 用户id,用于用户断开连接时,改变用户状态
  10.             ws.userId = message.userId;
  11.             // 上线
  12.             keepLatestOnlineList("onLine", message);
  13.           }
  14.           break;
  15.         case "message":
  16.           wss.clients.forEach(client => {
  17.             //  遍历所有客户端
  18.             if (!message.timestamp) {
  19.               message.timestamp = new Date().toISOString();
  20.             }
  21.             if (client.readyState === Websocket.OPEN) {
  22.               //  如果客户端处于打开状态
  23.               client.send(JSON.stringify(message), { binary: false }); //  发送消息
  24.             }
  25.           });
  26.           break;
  27.         default:
  28.           break;
  29.       }
  30.     });
复制代码
 
  3)被动断开说明用户已经脱离网站了,维护在线的列表
  
  1. ws.on("close", function() {
  2.       keepLatestOnlineList("close", { userId: ws.userId });
  3.     });
  4.   function keepLatestOnlineList(type, message) {
  5.     let index = onLineList.findIndex(item => item.userId === message.userId); //  在在线列表中查找用户
  6.     switch (type) {
  7.       case "onLine":
  8.         if (index === -1) {
  9.           //  如果用户不在在线列表中,则添加用户
  10.           onLineList.push({ userId: message.userId });
  11.         }
  12.         break;
  13.       case "close":
  14.         if (index !== -1) {
  15.           //  如果用户在在线列表中,则删除用户
  16.           onLineList.splice(index, 1);
  17.           console.log("有客户被断开");
  18.         }
  19.         break;
  20.       default:
  21.         break;
  22.     }
  23.   }
  24. }
复制代码
 
  二、 设置前端页面
1)模板部分
  
  1. <template>
  2.     <div class="app">
  3.         <div class="chat_container">
  4.             <div class="main_content_header">实时聊天</div>
  5.             <div class="chat-room">
  6.                 <div class="message-item" v-for="(item, index) in messageList" :key="index">
  7.                     <div v-if="item.isSystem" class="system-message">
  8.                         {{ formatSendTime(item.timestamp) }}
  9.                     </div>
  10.                     <!-- 左边通新内容 -->
  11.                     <div class="flex-left" v-if="item.userId !== userInfo.userId">
  12.                         <!--其他人的 头像 -->
  13.                         <div class="avater">
  14.                             <el-avatar src="https://picsum.photos/200/300"></el-avatar>
  15.                         </div>
  16.                         <div class="message-content">{{ item.content }}</div>
  17.                     </div>
  18.                     <div class="flex-right" v-else>
  19.                         <!--自己的 头像 -->
  20.                         <div class="message-content">{{ item.content }}</div>
  21.                         <div class="avater">
  22.                             <el-avatar>
  23.                                 <img src="../../../assets/images/avater.jpg" alt="">
  24.                             </el-avatar>
  25.                         </div>
  26.                     </div>
  27.                 </div>
  28.             </div>
  29.             <div class="send-box">
  30.                 <el-input type="text" v-model="yourMessage" />
  31.                 <el-button type="primary" @click="sendMesage">发送</el-button>
  32.             </div>
  33.         </div>
  34.     </div>
  35. </template>
复制代码

  2)逻辑部分
  
  1. <script setup >
  2. import { onMounted, ref } from 'vue'
  3. const yourMessage = ref('')
  4. const messageList = ref([])
  5. let ws = null
  6. const userInfo = ref({
  7.     userId: ""
  8. })
  9. const user = ref(sessionStorage.getItem('user'))
  10. // 发送消息
  11. function sendMesage() {
  12.     const timestamp = new Date().toISOString()
  13.     if (yourMessage.value) {
  14.         ws.send(JSON.stringify({
  15.             type: "message",
  16.             isSystem: true,
  17.             userId: userInfo.value.userId,
  18.             content: yourMessage.value,
  19.             timestamp: timestamp, // 添加时间戳
  20.         })
  21.         )
  22.         yourMessage.value = ''
  23.     }
  24. }
  25. const initWebSocket = () => {
  26.     ws = new WebSocket(`ws://localhost:4090?user=${String(user.value)}`)
  27.     ws.onopen = () => {
  28.         console.log('链接成功')
  29.         ws.send(JSON.stringify({
  30.             type: "init",
  31.             isSystem: true,
  32.             userId: userInfo.value.userId,
  33.             content: '欢迎来到聊天室',
  34.         })
  35.         )
  36.     }
  37.     ws.onmessage = (e) => {
  38.         const message = JSON.parse(e.data)
  39.         switch (message.type) { // 根据消息类型进行不同的操作
  40.             case "tips":
  41.                 console.log(message.content) // 如果消息类型为tips,则打印消息内容
  42.             case 'message':
  43.                 messageList.value.push(message) // 如果消息类型为message,则将消息添加到消息列表中
  44.                 console.log(messageList.value) // 打印消息列表
  45.                 break;
  46.             case 'onlineList':
  47.                 onlineList.value = message.onlineList // 如果消息类型为onlineList,则将在线用户列表赋值给onlineList
  48.                 break;
  49.         }
  50.     }
  51.     ws.onclose = () => {
  52.         console.log('连接关闭')
  53.     }
  54.     ws.onerror = () => {
  55.     }
  56. }
  57. onMounted(() => {
  58.     userInfo.value.userId = new Date().getTime().toString().slice(8)
  59.     initWebSocket()
  60. })
  61. // 时间格式化
  62. const formatSendTime = (sendTime) => {
  63.     const now = new Date();
  64.     const sendDate = new Date(sendTime);
  65.     const timeDiff = now - sendDate;
  66.     const oneDay = 24 * 60 * 60 * 1000;
  67.     if (timeDiff < 0) {
  68.         return "Invalid time"; // 或者其他错误处理
  69.     }
  70.     if (timeDiff < oneDay) {
  71.         return "今天" + formatTime(sendDate);
  72.     }
  73.     return sendDate.toLocaleDateString("zh-CN") + " " + formatTime(sendDate);
  74. };
  75. const formatTime = (date) => {
  76.     const hours = date.getHours().toString().padStart(2, "0");
  77.     const minutes = date.getMinutes().toString().padStart(2, "0");
  78.     return hours + ":" + minutes;
  79. };
  80. </script>
复制代码
 
  3)样式部分
    
  1. <style lang='less'>
  2. .app {
  3.     // width: 100vw;
  4.     // height: 100vh;
  5.     overflow: hidden;
  6.     // background-color: #fff;
  7.     display: grid;
  8.     place-items: center;
  9.     .chat_container {
  10.         width: 650px;
  11.         height: 650px;
  12.         overflow: hidden;
  13.         background-color: #fff;
  14.         border-radius: 8px;
  15.     }
  16. }
  17. .chat-room {
  18.     height: calc(100% - 110px);
  19.     padding: 10px;
  20.     overflow: auto;
  21.     background: #000;
  22. }
  23. .send-box {
  24.     border-top: 1px solid #eee;
  25.     display: flex;
  26.     align-items: center;
  27.     height: 60px;
  28. }
  29. .message-item {
  30.     width: 100%;
  31.     // margin: 0 auto;
  32.     margin-bottom: 10px;
  33.     .flex-left {
  34.         display: flex;
  35.         justify-content: flex-start;
  36.         .avater {
  37.             width: 40px;
  38.             height: 40px;
  39.             border-radius: 50%;
  40.             overflow: hidden;
  41.             display: flex;
  42.             justify-content: center;
  43.             align-items: center;
  44.             background-color: #eee;
  45.             margin-right: 10px;
  46.         }
  47.         .message-content {
  48.             min-height: 30px;
  49.             height: 40px;
  50.             line-height: 40px;
  51.             background: #fff;
  52.             border-radius: 8px;
  53.             padding: 0 10px;
  54.         }
  55.     }
  56.     .flex-right {
  57.         display: flex;
  58.         justify-content: flex-end;
  59.         .avater {
  60.             width: 40px;
  61.             height: 40px;
  62.             border-radius: 50%;
  63.             overflow: hidden;
  64.             display: flex;
  65.             justify-content: center;
  66.             align-items: center;
  67.             background-color: #eee;
  68.             margin-left: 10px;
  69.         }
  70.         .message-content {
  71.             min-height: 30px;
  72.             height: 40px;
  73.             line-height: 40px;
  74.             background: #fff;
  75.             border-radius: 8px;
  76.             padding: 0 10px;
  77.         }
  78.     }
  79. }
  80. .main_content_header {
  81.     width: 100%;
  82.     height: 50px;
  83.     border-radius: 5px;
  84.     background-color: #7de0bd;
  85.     display: flex;
  86.     align-items: center;
  87.     justify-content: center;
  88.     font-size: 16px;
  89. }
  90. .system-message {
  91.     font-size: 12px;
  92.     color: #fff;
  93.     display: flex;
  94.     justify-content: center;
  95.     align-items: center;
  96. }
  97. </style>
复制代码

完备代码
nodejs 部分
  
  1. const { WebSocketServer } = require("ws"); //  引入WebSocketServer模块
  2. const Websocket = require("ws");
  3. const WebSocket = require("ws"); //  引入WebSocket模块
  4. //定义一个在线列表
  5. const onLineList = []
  6. //设置端口号
  7. const wss = new WebSocket.Server({ port: 4090 });
  8. // 如果ws就代表初始化成功
  9. if(wss){
  10.   console.log('WebSocket初始化成功')
  11. }
  12. // 进行连接
  13. wss.on("connection", function connection(ws, request) {
  14. //   获取对应的用户名,来进行展示连接
  15.   const user = new URL(request.url, `http://${request.headers.host}`).searchParams.get('user');
  16.   console.log(`${user} 已连接`)
  17. //   设置欢迎语
  18.   let welCome = JSON.stringify({
  19.     type: "tips",
  20.     content:"欢迎回来~"
  21.   })
  22.   ws.send(welCome, { binary: false });
  23.   ws.on("error", (error) => {
  24.     console.log("WebSocket error:", error);
  25.   })
  26.    //注册收到消息的事件
  27.   ws.on("message", async function message(data) {
  28.     const message = JSON.parse(data);
  29.     switch (message.type) {
  30.       case "init":
  31.         if (message.userId) {
  32.           ws.userId = message.userId;
  33.           keepLatestOnlineList('online',message)
  34.         }
  35.         break;
  36.       case "message":
  37.         wss.clients.forEach(client => {
  38.         //   遍历所有的客户端
  39.           if(!message.timestamp) {
  40.             message.timestamp = new Date().toISOString();
  41.           }
  42.           if (client.readyState === Websocket.OPEN) {
  43.             //  如果客户端处于打开状态
  44.             client.send(JSON.stringify(message), { binary: false }); //  发送消息
  45.           }
  46.         })
  47.         break;
  48.         default:
  49.           break;
  50.     }
  51.   })
  52.   ws.on("close", function() {
  53.     keepLatestOnlineList("close", { userId: ws.userId });
  54.   });
  55. })
  56. function keepLatestOnlineList(type, message) {
  57.   let index = onLineList.findIndex(item => item.userId === message.userId); //  在在线列表中查找用户
  58.   switch (type) {
  59.     case "onLine":
  60.       if (index === -1) {
  61.         //  如果用户不在在线列表中,则添加用户
  62.         onLineList.push({ userId: message.userId });
  63.       }
  64.       break;
  65.     case "close":
  66.       if (index !== -1) {
  67.         //  如果用户在在线列表中,则删除用户
  68.         onLineList.splice(index, 1);
  69.         console.log("有客户被断开");
  70.       }
  71.       break;
  72.     default:
  73.       break;
  74.   }
  75. }
复制代码

  完成之后的样式如下
 喜欢点个关注吧~

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

金歌

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表