欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 国际 > vue3+nodeJs+webSocket实现聊天功能

vue3+nodeJs+webSocket实现聊天功能

2025/4/19 15:53:11 来源:https://blog.csdn.net/qq_65949679/article/details/147193527  浏览:    关键词:vue3+nodeJs+webSocket实现聊天功能

使用websocket 来实现聊天功能,主要是通过以下几点来实现的

一、使用nodejs来实现后端接口

     1、首先进行初始化

     

  const { WebSocketServer } = require("ws"); //  引入WebSocketServer模块const Websocket = require("ws");const WebSocket = require("ws"); //  引入WebSocket模块const onLineList = []; //  定义一个在线用户列表// 我们的port是8090const wss = new WebSocket.Server({ port: 8080 });// 如果有ws就代表初始化成功if (wss) {console.log("ws初始化成功");

2、进行连接 --- 设置进入的欢迎语

 const user = new URL(request.url, `http://${request.headers.host}`).searchParams.get('user');console.log(`${user} 已连接`);let welCome = JSON.stringify({type: "tips",content: "欢迎加入聊天室,现在我们开始畅聊吧"});ws.send(welCome, { binary: false });

 2)进行注册消息的事件

   

 ws.on("message", async function message(data) {const message = JSON.parse(data); //  将收到的数据解析为JSON格式switch (message.type //  根据消息类型进行不同的处理) {case "init":if (message.userId) {//  如果消息中包含用户id// 为当前的用户  ws链接绑定 用户id,用于用户断开连接时,改变用户状态ws.userId = message.userId;// 上线keepLatestOnlineList("onLine", message);}break;case "message":wss.clients.forEach(client => {//  遍历所有客户端if (!message.timestamp) {message.timestamp = new Date().toISOString();}if (client.readyState === Websocket.OPEN) {//  如果客户端处于打开状态client.send(JSON.stringify(message), { binary: false }); //  发送消息}});break;default:break;}});

 

3)被动断开说明用户已经离开网站了,维护在线的列表

 ws.on("close", function() {keepLatestOnlineList("close", { userId: ws.userId });});function keepLatestOnlineList(type, message) {let index = onLineList.findIndex(item => item.userId === message.userId); //  在在线列表中查找用户switch (type) {case "onLine":if (index === -1) {//  如果用户不在在线列表中,则添加用户onLineList.push({ userId: message.userId });}break;case "close":if (index !== -1) {//  如果用户在在线列表中,则删除用户onLineList.splice(index, 1);console.log("有客户被断开");}break;default:break;}}}

 

二、 设置前端页面

1)模板部分

<template><div class="app"><div class="chat_container"><div class="main_content_header">实时聊天</div><div class="chat-room"><div class="message-item" v-for="(item, index) in messageList" :key="index"><div v-if="item.isSystem" class="system-message">{{ formatSendTime(item.timestamp) }}</div><!-- 左边通新内容 --><div class="flex-left" v-if="item.userId !== userInfo.userId"><!--其他人的 头像 --><div class="avater"><el-avatar src="https://picsum.photos/200/300"></el-avatar></div><div class="message-content">{{ item.content }}</div></div><div class="flex-right" v-else><!--自己的 头像 --><div class="message-content">{{ item.content }}</div><div class="avater"><el-avatar><img src="../../../assets/images/avater.jpg" alt=""></el-avatar></div></div></div></div><div class="send-box"><el-input type="text" v-model="yourMessage" /><el-button type="primary" @click="sendMesage">发送</el-button></div></div></div>
</template>

2)逻辑部分

<script setup >
import { onMounted, ref } from 'vue'
const yourMessage = ref('')
const messageList = ref([])
let ws = null
const userInfo = ref({userId: ""
})const user = ref(sessionStorage.getItem('user'))// 发送消息
function sendMesage() {const timestamp = new Date().toISOString()if (yourMessage.value) {ws.send(JSON.stringify({type: "message",isSystem: true,userId: userInfo.value.userId,content: yourMessage.value,timestamp: timestamp, // 添加时间戳}))yourMessage.value = ''}
}const initWebSocket = () => {ws = new WebSocket(`ws://localhost:4090?user=${String(user.value)}`)ws.onopen = () => {console.log('链接成功')ws.send(JSON.stringify({type: "init",isSystem: true,userId: userInfo.value.userId,content: '欢迎来到聊天室',}))}ws.onmessage = (e) => {const message = JSON.parse(e.data)switch (message.type) { // 根据消息类型进行不同的操作case "tips":console.log(message.content) // 如果消息类型为tips,则打印消息内容case 'message':messageList.value.push(message) // 如果消息类型为message,则将消息添加到消息列表中console.log(messageList.value) // 打印消息列表break;case 'onlineList':onlineList.value = message.onlineList // 如果消息类型为onlineList,则将在线用户列表赋值给onlineListbreak;}}ws.onclose = () => {console.log('连接关闭')}ws.onerror = () => {}
}onMounted(() => {userInfo.value.userId = new Date().getTime().toString().slice(8)initWebSocket()
})
// 时间格式化
const formatSendTime = (sendTime) => {const now = new Date();const sendDate = new Date(sendTime);const timeDiff = now - sendDate;const oneDay = 24 * 60 * 60 * 1000;if (timeDiff < 0) {return "Invalid time"; // 或者其他错误处理}if (timeDiff < oneDay) {return "今天" + formatTime(sendDate);}return sendDate.toLocaleDateString("zh-CN") + " " + formatTime(sendDate);
};const formatTime = (date) => {const hours = date.getHours().toString().padStart(2, "0");const minutes = date.getMinutes().toString().padStart(2, "0");return hours + ":" + minutes;
};
</script>

 

3)样式部分

 

<style lang='less'>
.app {// width: 100vw;// height: 100vh;overflow: hidden;// background-color: #fff;display: grid;place-items: center;.chat_container {width: 650px;height: 650px;overflow: hidden;background-color: #fff;border-radius: 8px;}
}.chat-room {height: calc(100% - 110px);padding: 10px;overflow: auto;background: #000;
}.send-box {border-top: 1px solid #eee;display: flex;align-items: center;height: 60px;}.message-item {width: 100%;// margin: 0 auto;margin-bottom: 10px;.flex-left {display: flex;justify-content: flex-start;.avater {width: 40px;height: 40px;border-radius: 50%;overflow: hidden;display: flex;justify-content: center;align-items: center;background-color: #eee;margin-right: 10px;}.message-content {min-height: 30px;height: 40px;line-height: 40px;background: #fff;border-radius: 8px;padding: 0 10px;}}.flex-right {display: flex;justify-content: flex-end;.avater {width: 40px;height: 40px;border-radius: 50%;overflow: hidden;display: flex;justify-content: center;align-items: center;background-color: #eee;margin-left: 10px;}.message-content {min-height: 30px;height: 40px;line-height: 40px;background: #fff;border-radius: 8px;padding: 0 10px;}}
}.main_content_header {width: 100%;height: 50px;border-radius: 5px;background-color: #7de0bd;display: flex;align-items: center;justify-content: center;font-size: 16px;
}.system-message {font-size: 12px;color: #fff;display: flex;justify-content: center;align-items: center;
}
</style>

完整代码

nodejs 部分

const { WebSocketServer } = require("ws"); //  引入WebSocketServer模块
const Websocket = require("ws");
const WebSocket = require("ws"); //  引入WebSocket模块//定义一个在线列表const onLineList = []//设置端口号
const wss = new WebSocket.Server({ port: 4090 });// 如果ws就代表初始化成功if(wss){console.log('WebSocket初始化成功')
}// 进行连接wss.on("connection", function connection(ws, request) {
//   获取对应的用户名,来进行展示连接const user = new URL(request.url, `http://${request.headers.host}`).searchParams.get('user');console.log(`${user} 已连接`)//   设置欢迎语let welCome = JSON.stringify({type: "tips",content:"欢迎回来~"})ws.send(welCome, { binary: false });ws.on("error", (error) => {console.log("WebSocket error:", error);})//注册收到消息的事件ws.on("message", async function message(data) {const message = JSON.parse(data);switch (message.type) {case "init":if (message.userId) {ws.userId = message.userId;keepLatestOnlineList('online',message)}break;case "message":wss.clients.forEach(client => {//   遍历所有的客户端if(!message.timestamp) {message.timestamp = new Date().toISOString();}if (client.readyState === Websocket.OPEN) {//  如果客户端处于打开状态client.send(JSON.stringify(message), { binary: false }); //  发送消息}})break;default:break;}})ws.on("close", function() {keepLatestOnlineList("close", { userId: ws.userId });});
})function keepLatestOnlineList(type, message) {let index = onLineList.findIndex(item => item.userId === message.userId); //  在在线列表中查找用户switch (type) {case "onLine":if (index === -1) {//  如果用户不在在线列表中,则添加用户onLineList.push({ userId: message.userId });}break;case "close":if (index !== -1) {//  如果用户在在线列表中,则删除用户onLineList.splice(index, 1);console.log("有客户被断开");}break;default:break;}
}

完成之后的样式如下

 喜欢点个关注吧~

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词