当前位置: 首页 > news >正文

基于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>

相关文章:

  • 【数据分析基础】实验numpy、pandas和matplolib
  • Python中的Pandas数据处理与分析
  • Virtualbox 安装 ubuntu + qemu
  • 【WRF理论第四期】namelist.wps文件详述
  • 前端工程化工具系列(十)—— Browserslist:浏览器兼容性配置工具
  • VS环境Python:深度探索与实用指南
  • 在Nginx中配置php程序环境。
  • Kafka之Broker原理
  • 8.3 Go 包的组织结构
  • 轻松搞定阿里云域名DNS解析
  • cpp--lua--cpp执行lua
  • Qt/C++音视频开发76-获取本地有哪些摄像头名称/ffmpeg内置函数方式
  • 深度解读ChatGPT基本原理
  • QT Udp广播实现设备发现
  • Camtasia Studio怎么自动加字幕呢,Camtasia Studio有什么功能呢
  • E-HPC支持多队列管理和自动伸缩
  • node和express搭建代理服务器(源码)
  • PAT A1092
  • React Native移动开发实战-3-实现页面间的数据传递
  • React的组件模式
  • React系列之 Redux 架构模式
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • webpack入门学习手记(二)
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 检测对象或数组
  • 讲清楚之javascript作用域
  • 解决iview多表头动态更改列元素发生的错误
  • 目录与文件属性:编写ls
  • 悄悄地说一个bug
  • 一个完整Java Web项目背后的密码
  • - 语言经验 - 《c++的高性能内存管理库tcmalloc和jemalloc》
  • 转载:[译] 内容加速黑科技趣谈
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • ​LeetCode解法汇总518. 零钱兑换 II
  • ​Python 3 新特性:类型注解
  • #{}和${}的区别是什么 -- java面试
  • #565. 查找之大编号
  • #宝哥教你#查看jquery绑定的事件函数
  • #大学#套接字
  • (007)XHTML文档之标题——h1~h6
  • (1)无线电失控保护(二)
  • (2015)JS ES6 必知的十个 特性
  • (九)c52学习之旅-定时器
  • (每日一问)操作系统:常见的 Linux 指令详解
  • (三) prometheus + grafana + alertmanager 配置Redis监控
  • (学习日记)2024.01.09
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • .libPaths()设置包加载目录
  • .Net 4.0并行库实用性演练
  • .NET Framework、.NET Core 、 .NET 5、.NET 6和.NET 7 和.NET8 简介及区别
  • .NET MVC之AOP
  • .net 按比例显示图片的缩略图
  • .NET 的程序集加载上下文
  • .NET 实现 NTFS 文件系统的硬链接 mklink /J(Junction)