来咯来咯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 位版本&…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
