js+node.js+socket.io实现聊天功能(私聊,创建群聊)

您所在的位置:网站首页 qq怎么强制加入群聊聊天 js+node.js+socket.io实现聊天功能(私聊,创建群聊)

js+node.js+socket.io实现聊天功能(私聊,创建群聊)

2024-07-11 08:20| 来源: 网络整理| 查看: 265

效果图:

这里启动了四个客户端进行测试

1. 登录,以及获取在线用户列表

 

2. 私聊功能

 

3. 群聊功能

 

 

偶然发现了WebSocket, 发现这个可以实时通信,在线聊天,所以就做了一个聊天工具的demo,记录一下

源码

Socket.io

WebSocket是js原生自带的,而Socket.io相当于是对WebSocket进行封装的一个框架

官网说明: 介绍

Socket.io是一个WebSocket库,包括了客户端的js和服务器端的nodejs,它的目标是构建可以在不同浏览器和移动设备上使用的实时应用。它会自动根据浏览器从WebSocket、AJAX长轮询、Iframe流等等各种方式中选择最佳的方式来实现网络实时应用,非常方便和人性化,而且支持的浏览器最低达IE5.5

socket.io特点

实时分析: 将数据推送到客户端,这些客户端会被表示为实时计数器,图表或日志客户。实时通信和聊天: 只需几行代码便可写成一个Socket.IO的”Hello,World”聊天应用。二进制流传输: 从1.0版本开始,Socket.IO支持任何形式的二进制文件传输,例如:图片,视频,音频等。文档合并: 允许多个用户同时编辑一个文档,并且能够看到每个用户做出的修改。

官方文档中文版官方文档英文版

目录结构

 

 

 

新建文件夹 -> npm init -y 生成package.json 可以使用npm安装插件

使用npm安装express,socket.io

npm install express --save npm install socket.io --save 复制代码

安装完成的 package.json

{ "name": "websocketchat", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { "express": "^4.17.1", "socket.io": "^2.3.0" } } 复制代码 connection 和 disconnect

这里只是一个例子,介绍一下连接、断开、接收消息,不包含在项目内

这两个事件是框架本身的内置事件

connection 监听客户端连接

disconnect 监听客户端断开

客户端代码

index.html

Title window.socket = io(); socket.on('connect', () => { window.socket.on('success', data => { console.log(data) }) window.socket.on('quit', (id) => { console.log(`${id}连接断开`) }) }) 复制代码

服务器代码

server.js

const fs = require('fs'); var express = require('express'); var app = express(); var http = require('http').Server(app); var io = require("socket.io")(http); // 路由为/默认www静态文件夹 app.use('/', express.static(__dirname + '/src')); io.on('connection', socket => { socket.emit('success', '连接到服务器') socket.on('disconnect', () => { io.emit('quit', socket.id) }) }) http.listen(3002, () => { console.log('http://localhost:3002/index.html') }) 复制代码

启动服务器 运行node server.js

浏览器访问 http://localhost:3002/index.html

浏览器控制台输出: 连接到服务器

注意编辑器的字符集设置,否则可能显示乱码

可以开两个浏览器,谷歌,火狐分别访问http://localhost:3002/index.html

然后关掉火狐的访问页面,就可以看到连接断开的效果,谷歌控制台输出:TgkBeWIJK7G4hwlJAAAC连接断开

服务器代码中监听disconnect事件,发送消息为io.emit, 而不是socket.emit, 原因如下:

io.emit() 给所有客户端广播消息 socket.emit() 给该socket的客户端发送消息 火狐关掉访问页面,socket.emit('quit', socket.id)相当于给火狐这个客户端发消息,但是这个页面已经关掉了,自然是看不到的 io.emit('quit', socket.id) 给所有客户端广播消息,所以谷歌浏览器也可以收到这条消息 或 使用socket.broadcast.emit('quit', socket.id); socket.broadcast.emit() 向所有的socket连接进行广播,但是不包括发送者自身 复制代码

以下开始介绍此项目的功能及代码

登录,以及获取在线用户列表

客户端 main.js

function Chat() { this.userName // 当前登录用户名; this.userImg; // 用户头像 this.id; // 用户socketId 每个客户端有一个自己的socket.id 通过此id可以实现私聊 this.userList = []; // 好友列表 this.chatGroupList = []; // 群聊列表 this.sendFriend = ''; // 当前正在聊天好友的用户socketId this.sendChatGroup = ''; // 当前正在聊天的群聊的roomId this.messageJson = {}; // 好友消息列表 this.msgGroupJson = {}; // 群聊消息列表 this.tag = 0; // 0 我的好友面板 1 群聊面板 } 复制代码 Chat.prototype = { init() { this.userName = localStorage.getItem('userName'); this.userImg = localStorage.getItem('userImg'); this.selectClick(); // 注册页面按钮点击事件 this.setAllPorarait(); // 页面添加头像,图片,表情包 // 缓存中有用户名,头像则不用再次输入 if (this.userName && this.userImg) { $("#login-wrap").style.display = 'none'; this.login(this.userName, this.userImg); } else { $('.chat-btn').onclick = () => { let userName = $('.user-name').value; let userImg = $('.my-por').getAttribute('src'); this.login(userName, userImg); } } }, login(userName, userImg) { if (userName && userImg) { this.initSocket(userName, userImg); } }, initSocket(userName, userImg) { window.socket = io(); window.socket.on('connect', () => { $("#login-wrap").style.display = 'none'; $('.chat-panel').style.display = 'block'; this.userName = userName; this.userImg = userImg; this.id = window.socket.id; // 连接成功之后才能获取到id,每刷新一次浏览器,都会获取一个新的id let userInfo = { id: window.socket.id, userName: userName, userImg: userImg } // 获取用户名,头像,以及socketid 设置缓存并发送给服务器 localStorage.setItem('userName', userName); localStorage.setItem('userImg', userImg); window.socket.emit('login', userInfo); }) window.socket.on('userList', (userList) => { this.userList = userList; // 返回当前所有在线用户 this.drawUserList(); // 绘制好友列表 }) window.socket.on('quit', (id) => { this.userList = this.userList.filter(item => item.id != id) this.drawUserList(); }) } } 复制代码

服务器 server.js

let userList = []; io.on('connection', (socket) => { // 前端socket.emit('login')发送消息,后端socket.on('login')接收 socket.on('login', (userInfo) => { userList.push(userInfo); io.emit('userList', userList); /* io.emit(给所有客户端广播消息) = socket.emit(给该socket的客户端发送消息) + socket.broadcast.emit(发给所以客户端,不包括自己) */ }) // 退出(内置事件) socket.on('disconnect', () => { userList = userList.filter(item => item.id != socket.id) io.emit('quit', socket.id) }) }) 复制代码 私聊

流程 客户端A,客户端B私聊

客户端A的好友列表中点击B, 出现聊天面板, 标记当前聊天对象,this.sendFriend = 当前聊天对象的idA输入内容,点击发送按钮,使用window.socket.emit('sendMsg', data)发消息给服务器,并带有接收此消息客户端的id 客户端 main.js 消息发送按钮点击事件: let info = { sendId: this.id, // 发送者id id: this.sendFriend, // 接收者id userName: this.userName, // 发送者用户名 img: this.userImg, // 发送者头像 msg: $('.inp').innerHTML // 发送内容 } window.socket.emit('sendMsg', info) 复制代码 服务器socket.on('sendMsg', (data) => {})接收到此消息,socket.to(data.id).emit('receiveMsg', data) socket.on('sendMsg', (data) => { socket.to(data.id).emit('receiveMsg', data) }) 复制代码 对应id的客户端socket.on('receiveMsg', callback) 接收到私聊消息 window.socket.on('receiveMsg', data => { this.setMessageJson(data); // 将此条消息加入消息列表数据中 // 判断此条消息的sendId(发送者id) 是不是当前正在聊天的对象 // true 页面绘制聊天消息 if (data.sendId === this.sendFriend) { this.drawMessageList(); // 页面绘制聊天消息 } else { // false 好友头像左上角显示红点,提示此好友发来了新消息 $('.me_' + data.sendId).innerHTML = parseInt($('.me_' + data.sendId).innerHTML) + 1; $('.me_' + data.sendId).style.display = 'block'; } }) 复制代码 群聊 创建群聊 点击创建群聊按钮 -> 出现所有在线用户列表 -> 点击选择 -> 输入群名称 -> 确认创建 -> 客户端发送创建群聊消息给服务器 客户端 main.js window.socket.emit('createChatGroup', { masterId: chat.id, // 创建者id masterName: chat.userName, // 创建者用户名 // 房间id:可以自己设置房间id拼接规则 这个和用户的socketid不同 // 用户socketid是socket.id 拿到的, 房间id是自己自定义拼接的,只要保证不重复就可 roomId: 'room_' + chat.id + (Date.now()), chatGroupName: $('.chatGroupNameInput').value, // 群名 member: chat.chatGroupArr // 群成员,包含创建者 }) 复制代码

服务器接收到客户端发送的创建群聊消息

2.1 将此客户端,也就是创建者加入群聊socket.join(data.roomId); 2.2 存储此群聊数据chatGroupList[data.roomId] = data; 2.3 给群聊的所有成员发送邀请加入群聊的消息io.to(item.id).emit('chatGroupList', data)和当前群聊数据的消息 io.to(item.id).emit('createChatGroup', data)

服务器 server.js let chatGroupList = {}; // 创建群聊 socket.on('createChatGroup', data => { socket.join(data.roomId); chatGroupList[data.roomId] = data; // 群聊列表数据 // 群聊的每一个成员发送chatGroupList(当前群聊数据)、createChatGroup(创建群聊)消息 data.member.forEach(item => { io.to(item.id).emit('chatGroupList', data) io.to(item.id).emit('createChatGroup', data) }); }) 复制代码 客户端接收到chatGroupList消息,将数据加入群聊列表,并在页面上绘制群聊列表; 客户端 main.js window.socket.on('chatGroupList', chatGroup => { this.chatGroupList.push(chatGroup); this.drawChatGroupList(); // 绘制群聊列表 }) 复制代码 客户端接收到createChatGroup消息,给服务器发消息,说我要加入群聊socket.emit('joinChatGroup', data) 客户端 main.js window.socket.on('createChatGroup', (data) => { socket.emit('joinChatGroup', { id: this.id, userName: this.userName, info: data }) }) 复制代码 服务器接收到joinChatGroup消息,将当前客户端加入群聊socket.join(data.info.roomId); 并通知此群聊中的所有人,xxx加入了群聊 服务器 server.js // 加入群聊 socket.on('joinChatGroup', data => { socket.join(data.info.roomId); io.to(data.info.roomId).emit('chatGrSystemNotice', { roomId: data.info.roomId, msg: data.userName+'加入了群聊!', system: true });//为房间中的所有的socket发送消息, 包括自己 }) 复制代码 客户端接收到chatGrSystemNotice系统消息,将数据存储起来,并绘制到页面上 客户端 main.js window.socket.on('createChatGroup', (data) => { // 客户端给服务器发消息,说我要加入群聊 socket.emit('joinChatGroup', { id: this.id, userName: this.userName, info: data }) }) 复制代码 群聊聊天

流程同私聊相似,消息发送对象由个人id,变为了房间id

流程:

客户端A在群聊列表中选择了群聊B, 标记当前聊天的群聊roomId(this.sendChatGroup), 点击打开聊天面板,输入消息,点击发送,window.socket.emit('sendMsgGroup', info)服务器接收到sendMsgGroup socket.on('sendMsgGroup', (data) => { socket.to(data.roomId).emit('receiveMsgGroup', data); }) 复制代码 客户端receiveMsgGroup事件 window.socket.on('receiveMsgGroup', (data) => { this.setMsgGroupJson(data); // 此条消息添加到聊天数据列表中 // 判断收到的是不是当前群聊的,不是就标记红点,是就绘制聊天内容 if (data.roomId === this.sendChatGroup) { this.drawChatGroupMsgList(); // 绘制聊天内容 } else { $('.me_' + data.roomId).innerHTML = parseInt($('.me_' + data.roomId).innerHTML) + 1; $('.me_' + data.roomId).style.display = 'block'; } }) 复制代码 退出群聊 客户端A在自己的群聊列表中选择了群聊B点击退出,客户端发送消息 window.socket.emit('leave', { roomId: roomId, id: this.id, userName: this.userName }) 复制代码 服务器处理leave退出群聊事件 socket.on('leave', data => { socket.leave(data.roomId, () => { let member = chatGroupList[data.roomId].member; let i = -1; // 向群聊的每一个成员发送xx离开的通知消息,包括离开者 // 然后在成员数组member中删除离开的人 member.forEach((item, index) => { if (item.id === socket.id) { i = index; } io.to(item.id).emit('leaveChatGroup', { id: socket.id, // 退出群聊人的id roomId: data.roomId, msg: data.userName+'离开了群聊!', system: true }) }); if (i !== -1) { member.splice(i) } }); }) // socket.leave() 官网说明: socket.leave(room [, callback]) * room (串) * callback (功能) * Socket链接返回 从中删除客户端room,并可选地启动带有err签名的回调(如果有)。 断开后房间自动关闭。 复制代码 客户端leaveChatGroup window.socket.on('leaveChatGroup', data => { // 当前客户端退出群聊 if (data.id === this.id) { this.chatGroupList = this.chatGroupList.filter(item => item.roomId !== data.roomId) this.drawChatGroupList(); } else { // 其它成员离开了群聊,这里显示消息通知 this.setMsgGroupJson(data); if (this.tag) { $('.me_' + data.roomId).innerHTML = parseInt($('.me_' + data.roomId).innerHTML) + 1; $('.me_' + data.roomId).style.display = 'block'; this.drawChatGroupMsgList(); } else { $('.me-group-chat-tab').innerHTML = parseInt($('.me-group-chat-tab').innerHTML) + 1; $('.me-group-chat-tab').style.display = 'block'; $('.me_' + data.roomId).innerHTML = parseInt($('.me_' + data.roomId).innerHTML) + 1; $('.me_' + data.roomId).style.display = 'block'; } } }) 复制代码 小知识点 去掉input点击输入时出现的蓝色边框: outline: none; 实现input的效果,并可指定宽高 浏览器通知: // 获取权限 if (Notification && Notification.requestPermission){ Notification.requestPermission() } new Notification('新消息', { body: `${data.userName}: ${data.msg}`, icon: data.userImg }) 字体缩放 font-size: 12px; transform: scale(0.9); display: inline-block; 复制代码

此项目还有些不完善,比如:

好友列表是直接获取在线用户的,可以做成像群聊那样,申请添加好友,对方同意用户的群聊列表没有存储,刷新浏览器,就需要重新创建群聊新消息没做浏览器通知......

github源码

参考

官方文档中文版

简言 (YouChat) 感谢大佬

 转自https://juejin.im/post/5dc26343e51d4561f4177cc2



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3