基于websocket与node搭建简易聊天室

news2024/11/16 2:48:18

一、前言

上一篇文章介绍了websocket的详细用法与工具类的封装,本篇就基于websocket搭建一个简易实时的聊天室。

在本篇开始之前也可以去回顾一下websocket详细用法:WebSocket详解与封装工具类

在这里插入图片描述

二、基于node搭建后台websocket服务

首先确认本机电脑中是否安装node,可以通过cmd打开命令窗口运行node -v查看node版本;

  1. 建议创建一个空项目:
npm init
  1. 一路回车就行,然后就得到了一个package.json的配置文件;安装ws模块
npm i ws
  1. 新建app.js文件,源码如下:
const WebSocket = require('ws');
// 随机姓名
const names = ['赵', '钱', '孙', '李', '周', '吴', '郑', '王', '冯', '陈', '褚', '卫', '蒋', '沈', '韩', '杨', '朱', '秦', '尤', '许', '何',
	'吕', '施', '张', '孔', '曹', '严', '华', '金', '魏', '陶', '姜', '戚', '谢', '邹', '喻', '柏', '水', '窦', '章', '云', '苏', '潘', '葛',
	'奚', '范', '彭', '郎', '鲁', '韦', '昌', '马', '苗', '凤', '花', '方', '俞', '任', '袁', '柳', '酆', '鲍', '史', '唐', '费', '廉', '岑',
	'薛', '雷', '贺', '倪', '汤', '滕', '殷', '罗', '毕', '郝', '邬', '安', '常', '乐', '于', '时', '傅', '皮', '卞', '齐', '康', '伍', '余',
	'元', '卜', '顾', '孟', '平', '黄', '和', '穆', '萧', '尹'
];
// 获取随便昵称
const getRandom = (min, max) => {
	return Math.floor(Math.random() * (min - max) + max)
};
// 创建 WebSocket 服务器实例
const wss = new WebSocket.Server({
	port: 8080
});
// 监听连接事件
wss.on('connection', function(socket) {
	console.log('新连接');
	const randomIndex = getRandom(0, names.length - 1);
	socket.nickname = names.splice(randomIndex, 1)[0];
	sendMessageToClient( '连接成功!进入聊天室!');
	// 监听接收消息事件
	socket.on('message', function(message) {
		sendMessageToClient(message);
	});
	// 监听接收消息事件
	socket.on('close', function() {
		// 广播消息给所有客户端
		wss.clients.forEach(function each(client) {
			if (client.readyState === WebSocket.OPEN) {
				client.send(JSON.stringify({
					nickname: socket.nickname,
					msg: '退出聊天室!',
				}));
			}
		});
	});
	// 监听接收消息事件
	socket.on('error', function() {
		// 广播消息给所有客户端
		wss.clients.forEach(function each(client) {
			if (client.readyState === WebSocket.OPEN) {
				client.send(JSON.stringify({
					nickname: socket.nickname,
					msg: '网络不佳,连接失败 !',
				}));
			}
		});
	});
	// 发送消息到客户端
	function sendMessageToClient(message) {
		let targetMsg = message instanceof Buffer ? message.toString() : message;
		// 广播消息给所有客户端
		wss.clients.forEach(function each(client) {
			if (client.readyState === WebSocket.OPEN) {
				client.send(JSON.stringify({
					nickname: socket.nickname,
					msg: targetMsg,
				}));
			}
		});
	}
});

  1. 最后启动node服务:node app.js;

三、前端构建聊天室

3.1 确定功能点

  1. 会话框中展示聊天内容;
  2. 输入框与发送按钮发送消息内容;
  3. 连接websocket,监听实时消息展示到界面中;

3.2 界面结构搭建

在这里插入图片描述

代码结构:

<div class="main_container">
	<!-- 消息框 -->
	<div id="msgList"></div>
	<!-- 发送消息 -->
	<div class="controls">
		<input type="text" class="pushMsg" />
		<button id="btn">发送</button>
	</div>
</div>

3.3 代码逻辑

  1. 引入之前封装的websocket工具类;

    <script src="./utils/websocket.js"></script>
    
  2. 实例化连接websocket;

    const newWebSocket = new WebSocketClient('ws:localhost:8080');
    newWebSocket.connect();
    
  3. 定义消息列表,监听返回消息信息,根据消息展示到界面中;

    // 消息列表
    const msgList = [];
    newWebSocket.addEventListener('message', handleMessage);
    // 处理返回数据
    function handleMessage(msg) {
    	const msgData = JSON.parse(msg.data || '{}');
    	console.log(msgData, "返回数据====");
    	if (msgData && typeof msgData.msg === 'string' && !msgData.msg.includes('ping')) {
    		msgList.push({
    			name: msgData.nickname,
    			msg: msgData.msg,
    		});
    		const str = msgList.reduce((cur, next) => {
    			let curMsg = '';
    			if (next.msg.includes('连接')) {
    				curMsg = `<div class="center_msg">玩家:${next.name}_${next.msg}</div>`;
    			} else {
    				curMsg = `<div class="msg_line">
    										<div class="avatar">${next.name}</div>
    										<div class="msg_text">${next.msg}</div>
    									</div>`;
    			}
    			return cur += curMsg;
    		}, '');
    		$('#msgList').html(str);
    		// 获取设置了滚动属性的div标签
    		const div = document.getElementById('msgList');
    		// 设置滚动的顶点坐标为滚动的总高度
    		div.scrollTop = div.scrollHeight;
    	}
    }newWebSocket.addEventListener('message', handleMessage);
    // 处理返回数据
    function handleMessage(msg) {
    	const msgData = JSON.parse(msg.data || '{}');
    	console.log(msgData, "返回数据====");
    	if (msgData && typeof msgData.msg === 'string' && !msgData.msg.includes('ping')) {
    		msgList.push({
    			name: msgData.nickname,
    			msg: msgData.msg,
    		});
    		const str = msgList.reduce((cur, next) => {
    			let curMsg = '';
    			if (next.msg.includes('连接')) {
    				curMsg = `<div class="center_msg">玩家:${next.name}_${next.msg}</div>`;
    			} else {
    				curMsg = `<div class="msg_line">
    										<div class="avatar">${next.name}</div>
    										<div class="msg_text">${next.msg}</div>
    									</div>`;
    			}
    			return cur += curMsg;
    		}, '');
    		$('#msgList').html(str);
    		// 获取设置了滚动属性的div标签
    		const div = document.getElementById('msgList');
    		// 设置滚动的顶点坐标为滚动的总高度
    		div.scrollTop = div.scrollHeight;
    	}
    }
    
  4. 监听输入框回车事件,与发送按钮点击事件,发送消息;

    // 监听发送按钮
    $('#btn').on('click', sendMessage);
    
    // 输入框回车事件
    $('.pushMsg').keydown(function(event) {
    	if (event.key === 'Enter') {
    		sendMessage();
    	}
    });
    // 发送消息
    function sendMessage() {
    	const msg = $('.pushMsg').val();
    	if (msg) {
    		newWebSocket.send(`${msg}`);
    		$('.pushMsg').val('');
    	}
    }
    

四、涉及小知识点

  1. 取消滚动条的展示,发送消息后默认展示最下方数据;

    #msgList::-webkit-scrollbar {
    		width: 0;
    }
    
    // 获取设置了滚动属性的div标签
    const div = document.getElementById('msgList');
    // 设置滚动的顶点坐标为滚动的总高度
    div.scrollTop = div.scrollHeight;
    
  2. 输入框监听keydown事件,当key为Enter时发送消息(也可设置其他按键)

    // 输入框回车事件
    $('.pushMsg').keydown(function(event) {
    	if (event.key === 'Enter') {
    		sendMessage();
    	}
    });
    
  3. 取消input的光标进入的表框效果

    outline: none;
    
  4. 鼠标小手的出现

    cursor: pointer;
    

五、聊天室完整前端源码

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>聊天通信</title>
		<script src="./utils/jquery.min.js"></script>
		<script src="./utils/websocket.js"></script>
		<style>
			.main_container {
				width: 500px;
				margin: auto;
			}

			#msgList {
				width: 500px;
				height: 400px;
				overflow: auto;
				border: 2px solid #8491fe;
				border-radius: 10px;
				padding: 6px;
				background-color: #ebffff;
				box-sizing: border-box;
			}

			#msgList::-webkit-scrollbar {
				width: 0;
			}

			.msg_line {
				margin: 10px 0;
				display: flex;
				flex-wrap: wrap;
			}

			.avatar {
				width: 30px;
				height: 30px;
				border-radius: 50%;
				background-color: #77ffff;
				text-align: center;
				line-height: 30px;
				color: #333;
				font-size: 12px;
				margin-right: 6px;
			}

			.msg_text {
				display: inline-block;
				padding: 4px 12px;
				border-radius: 6px;
				background-color: #f0f1dd;
				font-size: 14px;
			}

			.center_msg {
				text-align: center;
				color: #f19597;
			}

			.controls {
				width: 100%;
				display: flex;
				justify-content: space-between;
				margin-top: 10px;
			}

			input {
				flex: 1;
				outline: none;
				height: 34px;
				line-height: 34px;
				border: 1px solid #d8d8d8;
				border-radius: 4px;
				padding: 0 4px;
				color: #333;
				margin-right: 12px;
			}

			#btn {
				width: 80px;
				height: 34px;
				cursor: pointer;
			}
		</style>
	</head>
	<body>
		<div class="main_container">
			<!-- 消息框 -->
			<div id="msgList"></div>
			<!-- 发送消息 -->
			<div class="controls">
				<input type="text" class="pushMsg" />
				<button id="btn">发送</button>
			</div>
		</div>
		<script src="./utils/websocket.js"></script>
		<script>
			// 消息列表
			const msgList = [];
			// 初始化websocket
			const newWebSocket = new WebSocketClient('ws:localhost:8080');
			newWebSocket.connect();
			window.NewWebSocket = newWebSocket;
			newWebSocket.addEventListener('message', handleMessage);
			// 处理返回数据
			function handleMessage(msg) {
				const msgData = JSON.parse(msg.data || '{}');
				console.log(msgData, "返回数据====");
				if (msgData && typeof msgData.msg === 'string' && !msgData.msg.includes('ping')) {
					msgList.push({
						name: msgData.nickname,
						msg: msgData.msg,
					});
					const str = msgList.reduce((cur, next) => {
						let curMsg = '';
						if (next.msg.includes('连接')) {
							curMsg = `<div class="center_msg">玩家:${next.name}_${next.msg}</div>`;
						} else {
							curMsg = `<div class="msg_line">
										<div class="avatar">${next.name}</div>
										<div class="msg_text">${next.msg}</div>
									</div>`;
						}
						return cur += curMsg;
					}, '');
					$('#msgList').html(str);
					// 获取设置了滚动属性的div标签
					const div = document.getElementById('msgList');
					// 设置滚动的顶点坐标为滚动的总高度
					div.scrollTop = div.scrollHeight;
				}
			}

			// 监听发送按钮
			$('#btn').on('click', sendMessage);

			// 输入框回车事件
			$('.pushMsg').keydown(function(event) {
				if (event.key === 'Enter') {
					sendMessage();
				}
			});
			// 发送消息
			function sendMessage() {
				const msg = $('.pushMsg').val();
				if (msg) {
					newWebSocket.send(`${msg}`);
					$('.pushMsg').val('');
				}
			}
		</script>
	</body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1788910.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手机录屏怎么没有声音?一键排查,轻松解决!

“手机录屏怎么没有声音&#xff1f;今天录制了一个线上的音乐会&#xff0c;结束的时候发现完全没有声音&#xff0c;我检查了手机的设置&#xff0c;录屏功能看起来是正常的&#xff0c;但为什么就是录不到声音呢&#xff1f;希望大家能帮我解答这个疑惑。” 随着智能手机的…

linux上VirtualBox使用

前言 最近想把唯一的windows系统装成linux&#xff0c; 但是确实存在一些特殊软件无法舍弃&#xff0c;所有装完linux需要用虚拟机装个windows 上来使用特定的一些软件&#xff08;不想用wine了&#xff09;。 还有对一些特定usb设备的透传&#xff0c;这样才能保证在虚拟机中…

数据库开发-Mysql03

目录 1. 多表查询 1.1 概述 1.1.1 数据准备 1.1.2 介绍 1.1.3 分类 1.2 内连接 1.3 外连接 1.4 子查询 1.4.1 介绍 1.4.2 标量子查询 1.4.3 列子查询 1.4.4 行子查询 1.4.5 表子查询 1.5 案例 2. 事务 2.1 介绍 2.2 操作 2.3 四大特性 3. 索引 3.1 介绍 3…

雷士大路灯有必要买吗?雷士、书客、孩视宝护眼落地灯实测PK!

面对市面上众多的护眼大路灯品牌&#xff0c;其中雷士、书客和孩视宝这几款大路灯受到了广泛的青睐&#xff0c;也是热度比较高的几款产品&#xff0c;正是因为这么多款大路灯&#xff0c;很多伙伴在看到文章推荐后很纠结&#xff0c;不知道如何选择&#xff0c;也有一部分伙伴…

【猫狗识别系统】图像识别Python+TensorFlow+卷积神经网络算法+人工智能深度学习

猫狗识别系统。通过TensorFlow搭建MobileNetV2轻量级卷积神经算法网络模型&#xff0c;通过对猫狗的图片数据集进行训练&#xff0c;得到一个进度较高的H5格式的模型文件。然后使用Django框架搭建了一个Web网页端可视化操作界面。实现用户上传一张图片识别其名称。 一、前言 …

RK3568技术笔记之一 RK3568总体介绍

RK3568是瑞芯微开发出一款很好用的芯片。我先把ROCKCHIP的原厂信息搬过来看看。 首先声明一下&#xff0c;这篇文章里的资讯版权归瑞芯微电子股份有限公司。毕竟是我转过来的嘛。 我自己的心得&#xff0c;版权就归我啦。 搬砖地址Rockchip-瑞芯微电子股份有限公司瑞芯微专注…

day34--Spring(三)

一、AOP 1 AOP简介 问题导入 问题1&#xff1a;AOP的作用是什么&#xff1f; 问题2&#xff1a;连接点和切入点有什么区别&#xff0c;二者谁的范围大&#xff1f; 问题3&#xff1a;请描述什么是切面&#xff1f; 1.1 AOP简介和作用【理解】 AOP(Aspect Oriented Progr…

TSINGSEE青犀视频汇聚机房动环智能监控方案,提升机房安全稳定性

一、背景需求 在当今信息化时代&#xff0c;机房作为数据中心的核心设施&#xff0c;承载着重要的网络设备和数据存储设备&#xff0c;其正常运行对于企业的数据安全和业务连续性至关重要。机房内部设备众多&#xff0c;且运行过程中涉及大量的数据交换和传输。一旦发生安全事…

合并多个h5文件

如图&#xff0c;bbt_frames下有多个视频文件夹&#xff0c;每个文件夹包括多个h5文件&#xff0c;将每个文件夹的h5文件合并成一个h5文件&#xff0c;并以该文件夹命名&#xff0c;存储至video_feature文件夹。 import os import h5py import numpy as npdef merge_h5_files(…

《深入浅出存储引擎》不同数据库背后的数据存储方案

在大数据和AI时代&#xff0c;数据库成为各类应用不可或缺的重要组成部分。而数据库中的数据依赖存储引擎进行管理&#xff0c;包括数据的存储、查询、更新和删除等。因此&#xff0c;在设计系统时&#xff0c;选择正确的数据库存储引擎方案变得尤为重要。这篇文章将以关系型、…

4.5-24V48V60V72V80V降压12V 0.5A 电动车车充USB充电方案芯片IC-H6601

H6601 降压开关转换器是一款为电动车USB充电设计的芯片。这款芯片内置功率MOSFET&#xff0c;具备宽输入工作电压范围&#xff08;4.5V 至 60V&#xff09;&#xff0c;能够持续输出电流0.5A&#xff0c;并且具有良好的负载和线性调整率。 电流控制模式使环路易稳定&#xff0c…

测试工具fio

一、安装部署 fio是一款优秀的磁盘IO测试工具&#xff0c;在Linux中比较常用于测试磁盘IO 其下载地址&#xff1a;https://brick.kernel.dk/snaps/fio-2.1.10.tar.gz 或者登录其官网&#xff1a;http://freshmeat.sourceforge.net/projects/fio/ 进行下载。 tar -zxvf fio-…

SpringBoot整合Skywalking

下载Java Agent 官网&#xff1a;https://skywalking.apache.org/downloads/ 提示&#xff1a;Agent最好到网上找一找之前的版本&#xff0c;新版本可能有bug&#xff0c;如果出现了并且网上也几乎没有这个版本的解决方法那么就切换之前的版本 本地启动时 -javaagent:d:\opt\…

ABB码垛机器人IRB260通讯板维修

ABB码垛机器人在现代制造业中发挥着重要作用&#xff0c;而机器人通讯板维修对于确保机器人的正常运行至关重要。 通讯板是ABB码垛机器人与控制系统之间进行数据传输的桥梁。它负责接收控制系统的指令&#xff0c;并将机器人的运行数据反馈给控制系统。如果通讯板出现故障&…

郑州永兴牌饲料机械设备厂家

作为专注生产饲料机械设备厂家&#xff0c;郑州永兴不仅拥有完善的生产线和制造工艺&#xff0c;更在技术创新和产品研发方面走在了行业前列。 郑州永兴深知饲料机械设备对于饲料生产的重要性&#xff0c;因此始终坚持以市场需求为导向&#xff0c;不断推陈出新。其生产的饲…

黄金票据~

一. 黄金票据原理 黄金票据一般是伪造的TGT,生成这个TGT&#xff0c;不需要和KDC进行校验&#xff0c;金票可以在本地直接生成&#xff0c;生成的的金票在非域机器和域内机器都可以使用 黄金票据的作用&#xff1a; 可以用来权限维持 可以用来横向移动二. 利用条件 1. 必须…

Docker-compose 编排lnmp(dockerfile) 完成Wordpress

一、部署 Nginx 镜像 1. 建立工作目录 mkdir /opt/lnmp/nginx -pcd /opt/lnmp/nginx#上传 nginx 安装包 nginx-1.12.0.tar.gz#上传 wordpress 服务包 wordpress-4.9.4-zh_CN.tar.gz mkdir /opt/lnmp/nginx/htmltar zxvf wordpress-4.9.4-zh_CN.tar.gz -C /opt/lnmp/nginx/html…

html 使用svg矢量图时无法 调整宽高问题解决,不能像图片一样设置宽高比例问题

引入的路径后加 #svgView(preserveAspectRatio(none)) 具体代码如下 修改前 <img src"/assets/svgs/full_screen_full.svg" class"im"> 修改后 <img src"/assets/svgs/full_screen_full.svg#svgView(preserveAspectRatio(none))" cla…

TypeScript学习(一):开发环境搭建

官方文档搭建参考 https://learn.microsoft.com/zh-cn/training/modules/typescript-get-started/ 1.下载node.js https://nodejs.org/en/download 2.下载vscode https://code.visualstudio.com/ 3.在线ts的测试工具 https://www.typescriptlang.org/play/ 4.下载typescr…

pyqt QAxWidget 读写Excel文件

QaxWidget相比openpyxl 的方式区别是提供了图形界面&#xff0c;excel的输入修改不用再编写代码&#xff0e;activeX技术是个过时的技术&#xff0c;发挥下余热&#xff0e; # -*- coding: utf-8 -*- from PyQt5.QAxContainer import QAxWidget from PyQt5.QtWidgets import …