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

一、前言

上一篇文章介绍了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 = [];// 初始化websocketconst 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.mzph.cn/web/22341.shtml

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

相关文章

c# 操作Microsoft Access数据库

数据库结构为&#xff1a; public static string connting "数据库路径&#xff1a;如&#xff1a;D:\\xxx.mdb";//插入public bool InsertToFile(string casenumber, int lastrowid, int pagecount){bool result true;try{string connString $"ProviderMicr…

在nodeJS 中实现langchain 的Agent (实验笔记)

在nodeJS 中实现langchain 的Agent 实验过程记录如下&#xff1a; 1 构建一个Agent &#xff0c;使用两个工具 Calculator和TavilySearchResults 2 Tavily Search的API key 的获取 之前一直找不到一个合适的搜索引擎&#xff0c;Google Search 被墙&#xff0c;bing Search …

【Linux】进程(5):命令行参数

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家了解Linux进程&#xff08;5&#xff09;&#xff1a;命令行参数&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 &#xff08;A&#xff09;为什么要有命令…

Paraformer解读(1)基于self-attention和dfsmn的encoder

DFSMN SAN-M python实现 import torch import torch.nn as nn import torch.nn.functional as Fclass PositionalEncoding(nn.Module):def __init__(self, d_model, dropout0.1, max_len5000):super(PositionalEncoding, self).__init__()self.dropout nn.Dropout(pdropout)p…

你管这破玩意儿叫负载均衡?

你管这破玩意儿叫负载均衡? 那么四层负载均衡器是如何工作的呢总结 相信大家都听过这样的一道经典面试题&#xff1a;「请说出在淘宝网输入一个关键词到最终展示网页的整个流程&#xff0c;越详细越好」 这个问题很难&#xff0c;涉及到 HTTP&#xff0c;TCP&#xff0c;网关…

Python第二语言(二、Python语言基础)

目录 1. python中常用的6中数据类型 2. Print语句&#xff08;输出程序&#xff09; 3. 字面量 4. 注释 5. 变量 6. 数据类型 7. type()语句&#xff1a;查询数据类型 8. 数据类型转换语句 9. 标识符 10. 算术运算符 11. 赋值运算符 && 复合赋值运算符 12. …

3. redis常见部署架构

redis常见部署架构 一、redis常见部署架构1、常见部署架构2、多实例部署2.1 规划安装目录、配置文件2.2.2 编辑实例配置文件2.2.3 启动实例2.2.4 测试数据读写 3、redis主从复制3.1 规划3.2 从服务器配置3.3 验证主从状态3.4 主从角色切换 4、分片集群4.1 原理4.2 分片集群的部…

CSAPP Lab02——Bomb Lab完成思路详解

看见的看不见的 瞬间的永恒的 青草长啊大雪飘扬 ——月亮之上 完整代码见&#xff1a;CSAPP/bomb at main SnowLegend-star/CSAPP (github.com) 01 字符串比较 简单的把输入的字符串和地址“0x402400”内早已存储的字符串相比较。如果两个字符串相等则函数返回&#xff0c;否…

【Git】如何不管本地文件,强制git pull

要在 Git 中强制执行 git pull 操作&#xff0c;忽略本地文件的更改&#xff0c;可以按照以下步骤操作&#xff1a; 保存当前工作状态&#xff1a;如果你有未提交的更改&#xff0c;可以使用 git stash 将这些更改存储起来。 git stash强制拉取最新代码&#xff1a;使用 git re…

ffmpeg视频编码原理和实战-(2)视频帧的创建和编码packet压缩

源文件&#xff1a; #include <iostream> using namespace std; extern "C" { //指定函数是c语言函数&#xff0c;函数名不包含重载标注 //引用ffmpeg头文件 #include <libavcodec/avcodec.h> } //预处理指令导入库 #pragma comment(lib,"avcodec.…

9.抽象类和接口

抽象类 抽象类概念 在面向对象的概念中&#xff0c;所有的对象都是通过类来描绘的&#xff0c;但是反过来&#xff0c;并不是所有的类都是用来描绘对象的&#xff0c;如果一个类中没有包含足够的信息来描绘一个具体的对象&#xff0c;这样的类就是抽象类 比如&#xff1a; 我…

error /var/lib/jenkins/workspace/*/node_modules/node-sass: Command failed.

原因&#xff1a;node-sass版本不一致 版本图&#xff1a; 解决方案&#xff1a; 进入到jenkins项目目录下&#xff0c;修改package.json文件 将7.0.1改成6.0.1版本

鸿蒙Ability Kit(程序框架服务)【UIExtensionAbility】

UIExtensionAbility 概述 [UIExtensionAbility]是UI类型的ExtensionAbility组件&#xff0c;需要与[UIExtensionComponent]一起配合使用&#xff0c;开发者可以在UIAbility的页面中通过UIExtensionComponent嵌入提供方应用的UIExtensionAbility提供的UI。UIExtensionAbility会…

匈牙利匹配算法

一 什么是匈牙利匹配算法 匈牙利算法是一种解决二分图最大匹配问题的算法。在二分图中&#xff0c;将左边的点称为X集合&#xff0c;将右边的点称为Y集合&#xff0c;我们需要在X集合和Y集合之间建立一个双向边集合&#xff0c;使得所有的边都不相交。如果我们能够找到一个最大…

C++ Thread多线程并发记录(8)生产者-消费者模型与信号量(条件变量)

一.生产者-消费者模型 生产者-消费者模型是一个十分经典的多线程并发协作模式。所谓的生产者-消费者&#xff0c;实际上包含了两类线程&#xff0c;一种是生产者线程用于生产数据&#xff0c;另一种是消费者线程用于消费数据&#xff0c;为了解耦生产者和消费者的关系&#xff…

Opencv 色彩空间

一 核心知识 色彩空间变换&#xff1b; 像素访问&#xff1b; 矩阵的、-、*、、&#xff1b; 基本图形的绘制 二 颜色空间 RGB&#xff1a;人眼的色彩空间&#xff1b; OpenCV默认使用BGR&#xff1b; HSV/HSB/HSL; YUV(视频); 1 RGB 2 BGR 图像的多种属性 1 访问图像(Ma…

人工智能大模型的进化之路:探索如何让它们变得更“聪明”

一、引言 在人工智能&#xff08;AI&#xff09;领域&#xff0c;大模型凭借其强大的处理能力和广泛的应用前景&#xff0c;已经成为研究的热点。然而&#xff0c;尽管这些模型在多个领域展现出了惊人的能力&#xff0c;但它们仍然面临着理解力、泛化能力和适应性等方面的挑战…

学习Java的日子 Day51 数据库,DDL,DML

Day51 MySQL 1.数据库 数据库&#xff08;database&#xff09;就是一个存储数据的仓库。为了方便数据的存储和管理&#xff0c;它将数据按照特定的规律存储在磁盘上。通过数据库管理系统&#xff0c;可以有效地组织和管理存储在数据库中的数据 MySQL就是数据库管理系统&#…

VisionPro界面乱序或字体排版异常,字体不适应界面窗口大小

很多人在安装Visionpro后都遇到了一个界面显示异常的问题&#xff1a; 打开visionpro后字体大小不统一,显示不全或显示在其他窗口之上&#xff0c;如下所示。 解决该问题&#xff0c;首先关闭Visionpro软件&#xff0c;右击软件选择属性->兼容性。勾选兼容模式下面的方框。…

WebStorm 2024.1.1 Mac激活码 前端开发工具集成开发环境(IDE)

WebStorm 2024 Mac激活码 搜索Mac软件之家下载WebStorm 2024 Mac激活版 WebStorm 2024 功能介绍 WebStorm 2024是由JetBrains公司开发的一款专为前端开发设计的集成开发环境&#xff08;IDE&#xff09;。它提供了一整套功能&#xff0c;旨在提高Web开发者的工作效率和代码质…