来咯来咯webSocket
在项目总目录下 设置socketServe文件夹 里面创建下面两个文件
使用的时候需要开启 node webSocket.cjs
var { Server } = require('ws');
var moment = require('moment');const wss = new Server({port: 8888
});let id = 0;
let onlineMemberList = [];
const defaultUser = 'user';wss.on('connection', function (ws, req) {id++;ws.id = id;let reqUser = req.url.split('?')[1];let name = reqUser && reqUser.split('=')[1];let userName;if (name) {userName = decodeURIComponent(name);} else {userName = defaultUser + id;}const userInfo = {userName: userName,socketId: id,date: moment().format('MMMM Do YYYY, h:mm:ss a')};for (let i = 0; i < onlineMemberList.length; i++) {if (userInfo.userName === onlineMemberList[i].userName) {onlineMemberList[i] = userInfo;wss.clients.forEach(itemWs => {itemWs.send(JSON.stringify(onlineMemberList));});return;}}onlineMemberList.push(userInfo);wss.clients.forEach(itemWs => {itemWs.send(JSON.stringify(onlineMemberList));});ws.on('message', function (data) {console.log(data);const newData = JSON.parse(data);newData.serveDate = moment().format('MMMM Do YYYY, h:mm:ss a');wss.clients.forEach(itemWs => {itemWs.send(JSON.stringify(newData));});});ws.on('close', function (ev) {console.log('客户端断开连接');onlineMemberList = onlineMemberList.filter(item => {return item.socketId !== ws.id;});wss.clients.forEach(itemWs => {itemWs.send(JSON.stringify(onlineMemberList));});console.log(onlineMemberList, 'onlineMemberList');console.log(ws.id, 'ws.id');});ws.on('error', function (ve) {console.log('客户端异常');});
});console.log('webSocket服务已开启,端口为:8888');
{"type": "module"
}
页面展示 监听消息
<template><div class="chating"><div class="chating-wrap"><div class="title">聊天页面</div><div class="chating-content"><div class="chating-body"><div class="chating-list"><ul class="chating-records" ref="chatingList"><div:key="index"v-for="(item, index) in chatingRecords"><liclass="other"v-show="item.nickName != myNickName"><imgalt="用户头像"src="@/assets/logo.svg"/><div class="record-text-wrap"><div class="nick-name">{{item.nickName}}</div><div class="record-text">{{item.message}}</div></div></li><liclass="my"v-show="item.nickName == myNickName"><div class="record-text-wrap"><!-- <div class="nick-name">迷离</div> --><div class="record-text">{{item.message}}</div></div><imgalt="用户头像"src="@/assets/logo.svg"/></li></div></ul></div><div class="chating-btns"><inputclass="input-text"placeholder="请输入聊天内容"type="text"v-model="text"@keydown.native.enter="sendData"/><button@click="sendData"class="send">发送</button></div></div><div class="chating-online-number"><div class="online-num">在线用户{{userList.length}}</div><ul v-if="userList.length > 0"><li:key="index"class="user"v-for="(item, index) in userList"><imgalt="用户头像"src="@/assets/logo.svg"/><span>{{ item.userName }}</span><span v-if="userList.includes(item)">(在线)</span><span v-else>(离线)</span></li></ul><button @click="loginOutHandler">退出群聊</button></div></div></div><divclass="login"v-if="showLogin"><div class="opacity-wrap"><div>用户名:<inputclass="user-name"v-model="userName"/></div><button@click="loginHandler"class="login-btn">登录</button></div></div></div>
</template><script>
export default {data() {return {text: '',socketUrl: 'ws://localhost:8888?userName=',client: null,chatingRecords: [],myNickName: '',userName: '',showLogin: false,userList: [],onlineStatus: false // 添加在线状态变量,默认为 false 表示离线}},created() {console.log('created')// this.initChaing()},mounted() {console.log('mounted')},methods: {/* 初始化聊天,连接socket */initChaing() {let that = thisif (window.WebSocket) {/* webSocket 连接服务器 */this.client = new WebSocket(this.socketUrl + this.myNickName)/* 监听客户端连接 */this.client.onopen = function (ev) {if (ev.type === 'open') {console.log('客户端连接socket服务')that.onlineStatus = true; // 更新在线状态为 true}}/* 监听服务端发送的消息 */this.client.onmessage = function (ev) {let data = JSON.parse(ev.data)/* 用户在线信息接收的是一个jsony数组 */if (data instanceof Array === true) {that.userList = data // 在线用户数量变化} else {/* 聊天信息接收的是一个json对象 */that.chatingRecords.push(data) // 在线用户聊天}}/* 监听服务端关闭 */this.client.onclose = function (ev) {console.log('socket服务已关闭')that.client = null // 客户端或者是服务端断开后,将webSocket实例清除that.onlineStatus = false; // 更新在线状态为 false}/* 监听服务端异常 */this.client.onerror = function () {if (!that.client) {console.log('socket服务连接失败')}that.loginOutHandler()}} else {alert('该浏览器不支持webSocket,请使用主流浏览器,如chrome')}},loginHandler() {this.myNickName = this.userName;this.showLogin = false;this.onlineStatus = true; // 用户登录成功后将在线状态更新为 truethis.initChaing();},loginOutHandler() {this.client.close()this.client = null // 客户端或者是服务端断开后,将webSocket实例清除this.$router.push('/')},sendData() {if (!this.myNickName) {alert('请登录')this.showLogin = truereturn}if(this.text === ''){return}let data = {nickName: this.myNickName, // 将 myNickName 改为 nickNameuid: new Date().getTime(),message: this.text,date: new Date()}if (this.client) {this.client.send(JSON.stringify(data))this.text = ''// 在添加新消息后,将列表容器滚动到底部this.$nextTick(() => {let chatList = this.$refs.chatingList;if (chatList) {// 计算滚动位置,考虑到边距和边框let scrollHeight = chatList.scrollHeight;let clientHeight = chatList.clientHeight;let offset = 54; // 考虑到可能的额外偏移量chatList.scrollTop = scrollHeight - clientHeight + offset;}});} else {console.log('socket服务连接失败,正在重新连接服务..')this.initChaing()}}},beforeDestroy() {this.client.close()}
}
</script><style>
.login {width: 100vw;height: 100vh;position: fixed;top: 0;left: 0;background: rgba(0, 0, 0, 0.6);display: flex;justify-content: center;align-items: center;
}
.opacity-wrap {width: 500px;height: 300px;background: #fff;display: flex;justify-content: center;align-items: center;flex-direction: column;
}
.user-name {font-size: 16px;padding: 5px;text-indent: 10px;
}
.login-btn {font-size: 20px;background: cornflowerblue;color: 20px;margin-top: 30px;color: #fff;border: none;outline: none;padding: 10px 20px;border-radius: 10px;
}
ul {list-style: none;margin: 0;padding: 0;
}
.chating {width: calc(100vw - 200px);max-width: 800px;max-height: 600px;overflow-y: auto;border: 20px solid lightcyan;border-radius: 20px;margin: 0 auto 0;
}
.title {background: cornflowerblue;color: #fff;padding: 5px 0 5px;
}
.chating-content {width: 100%;display: flex;justify-content: space-between;
}
.chating-body {flex: 1;display: flex;flex-direction: column;justify-content: space-between;background: #f3f3f3;
}
.chating-list {flex: 1;border: 1px solid cornflowerblue;
}
.chating-records {padding: 10px;min-height: 300px;max-height: 600px;overflow-y: auto;
}
.chating-records li {margin-bottom: 20px;
}
.chating-records .other {display: flex;justify-content: start;align-items: flex-start;
}
.chating-records .my {display: flex;justify-content: flex-end;align-items: center;
}.chating-records img {width: 36px;height: 36px;/* border-radius: 50%; */margin-right: 15px;background: rgba(228, 157, 228,0.5);
}
.chating-records .my img {margin-right: 0;margin-left: 15px;
}
.chating-records .other .record-text-wrap {display: flex;flex-direction: column;align-items: flex-start;
}
.chating-records .my .record-text-wrap {display: flex;flex-direction: column;align-items: flex-end;
}
.nick-name {font-size: 14px;margin-bottom: 5px;color: #666;
}
.record-text {max-width: 260px;text-align: left;font-size: 14px;padding: 5px;background: #fff;border-radius: 5px;
}.chating-btns {background: burlywood;padding: 10px;display: flex;align-items: center;justify-content: center;
}
.input-text {font-size: 16px;border: none;outline: none;padding: 5px 0 5px 5px;
}
.send {font-size: 16px;border: none;outline: none;padding: 4px 15px;margin-left: 20px;
}.online-num {font-size: 12px;padding-bottom: 15px;
}
.chating-online-number {padding: 15px;height: 100%;
}
.chating-online-number ul {list-style: none;margin: 0;padding: 0;min-width: 120px;max-height: 580px;overflow-y: auto;
}
.user {display: flex;justify-content: space-between;align-content: center;line-height: 20px;font-size: 12px;border-bottom: 1px solid aqua;padding: 10px;margin-bottom: 5px;
}
.user img {width: 20px;height: 20px;border-radius: 50%;margin-right: 5px;
}
</style>
相关文章:
来咯来咯webSocket
在项目总目录下 设置socketServe文件夹 里面创建下面两个文件 使用的时候需要开启 node webSocket.cjs var { Server } require(ws); var moment require(moment);const wss new Server({port: 8888 });let id 0; let onlineMemberList []; const defaultUser user;wss…...
Android CALL关于电话音频和紧急电话设置和获取
获取音频服务,设置音源类型:电话类型和获取最大电话音量,响铃模式 private AudioManager mAudioManager; mAudioManager (AudioManager) getSystemService(AUDIO_SERVICE); mAudioManager.setStreamVolume(AudioManager.STREAM_VOIC…...

【春秋云镜】CVE-2023-23752
目录 CVE-2023-23752漏洞细节漏洞利用示例修复建议 春秋云镜:解法一:解法二: CVE-2023-23752 是一个影响 Joomla CMS 的未授权路径遍历漏洞。该漏洞出现在 Joomla 4.0.0 至 4.2.7 版本中,允许未经认证的远程攻击者通过特定 API 端…...
C#-__DynamicallyInvokable
[__DynamicallyInvokable] 属性是用于 .NET Framework 中的特性之一。这个特性通常用于标记在动态语言运行时中可以进行调用的方法或属性。 当一个方法或属性被标记为 [__DynamicallyInvokable],它表明这个成员在动态语言的环境中是可调用的。换句话说,…...

2024年最新10款顶级项目管理软件排行
项目管理软件在现代项目管理中扮演着至关重要的角色,它不仅仅是一个工具,更是一种高效、系统化的方法来管理和优化项目流程,帮助项目经理和团队成员快速了解项目状态,加速项目进展。 进度猫 进度猫是一款以甘特图为向导的轻量级…...
Python NLTK进阶:深入自然语言处理
目录 Python NLTK进阶:深入自然语言处理 1. 文本处理技术 1.1 命名实体识别(NER) 1.2 共指消解 2. 语义分析 2.1 语义角色标注(SRL) 2.2 词义消歧(Word Sense Disambiguation) 3. 机器学…...
【React 的理解】
谈一谈你对 React 的理解 对待这类概念题,讲究一个四字口诀“概用思优”,即“讲概念,说用途,理思路,优缺点,列一遍” 。 React 是一个网页 UI 框架,通过组件化的方式解决视图层开发复用的问题&a…...

软件压力测试有多重要?北京软件测试公司有哪些?
软件压力测试是一种基本的质量保证行为,它是每个重要软件测试工作的一部分。压力测试是给软件不断加压,强制其在极限的情况下运行,观察它可以运行到何种程度,从而发现性能缺陷。 在数字化时代,用户对软件性能的要求越…...

十四届蓝桥杯STEMA考试Python真题试卷第二套第五题
来源:十四届蓝桥杯STEMA考试Python真题试卷第二套编程第五题 本题属于迷宫类问题,适合用DFS算法解决,解析中给出了Python中 map() 和列表推导式的应用技巧。最后介绍了DFS算法的两种常见实现方式——递归实现、栈实现,应用场景——迷宫类问题、图的连通性、树的遍历、拓朴排…...

虚拟机 Ubuntu 扩容
文章目录 一、Vmware 重新分配 Ubuntu 空间二、Ubuntu 扩容分区 一、Vmware 重新分配 Ubuntu 空间 先打开 Vmware ,选择要重新分配空间的虚拟机 点击 编辑虚拟机设置 ,再点击 硬盘 ,再点击 扩展 选择预计扩展的空间,然后点击 扩展…...
内网远程连接解决方案【Frp】
1、从https://github.com/fatedier/frp/releases下载需要的版本,如 frp_0.61.0_linux_amd64.tar.gz 2、解压tar -xvf frp_0.61.0_linux_amd64.tar.gz 3、配置服务端【外网云主机】,修改ftps.toml文件: bindPort 7000 vhostHTTPPort8000…...

浙江欧瑞雅装饰材料有限公司:空间的艺术,定制的智慧!
浙江欧瑞雅装饰材料有限公司:空间的艺术,定制的智慧!在追求生活品质与空间利用并重的当下,浙江欧瑞雅装饰材料有限公司以其卓越的全屋定制服务,成为了众多家庭优化居住环境的理想选择。这家公司,凭借其深厚…...

jfrog artifactory oss社区版,不支持php composer私库
一、docker安装 安装环境:centos操作系统,root用户。 如果是mac或ubuntu等操作系统的话,会有许多安装的坑等着你。 一切都是徒劳,安装折腾那么久,最后还是不能使用。这就是写本文的初衷,切勿入坑就对了。 …...
华为OD机试真题-用户调度问题-2024年OD统一考试(E卷)
最新华为OD机试考点合集:华为OD机试2024年真题题库(E卷+D卷+C卷)_华为od机试题库-CSDN博客 每一题都含有详细的解题思路和代码注释,精编c++、JAVA、Python三种语言解法。帮助每一位考生轻松、高效刷题。订阅后永久可看,发现新题及时跟新。 题目描述 在通信系统中,一…...
前端与后端长连接 方法
1、SSE 一、SSE的主要特点 单向通信:SSE是服务器向客户端的单向通信,客户端不能直接通过SSE向服务器发送消息。文本数据流:SSE传输的主要是文本数据(通常是JSON格式),不适合二进制数据。自动重连&a…...

建议AI产品经理面试准备到这个程度再去
AI产品经理的面试整体的难度不高,和面试官探讨了很多关于做AI平台的方向和思考,其中AI智能客服的搭建被问到的次数最多!面试官也解释了很多他们现在碰到的业务问题和解决方案,收获还是很多的~ ⏭️AI智能客服项目如下 1️⃣ 【预…...

智能交通的未来:深度学习如何改变车辆检测游戏规则
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...
家具制造的效率与美观并重,玛哈特矫平机让家具产品更具竞争力。
在家具制造业中,效率与美观度的双重追求一直是企业关注的焦点。一方面,高效率的生产流程能够缩短交货周期,降低成本,提升企业的市场竞争力;另一方面,美观大方的家具设计则能吸引消费者的目光,提…...

交叉编译gcc
文章目录 前言下载gcc下载依赖项下载其他依赖项 configure选项--enable-languagesCXX和CXX_FOR_TARGETCFLAGS和CXXFLAGS--with-build-time-tools 使用小结 前言 前一阵用qemu做了个基于virt板卡的虚拟机,在不断完善,这两天想添加一个gcc进去,…...

[VUE]框架网页开发1 本地开发环境安装
前言 其实你不要看我的文章比较长,但是他就是很长!步骤其实很简单,主要是为新手加了很多解释! 步骤一:下载并安装 Node.js 访问 Node.js 官网: Node.js — Download Node.js 下载 Windows 64 位版本&…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
vue3 daterange正则踩坑
<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...