来咯来咯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 位版本&…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
【Go语言基础【12】】指针:声明、取地址、解引用
文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...
Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...
Java数组Arrays操作全攻略
Arrays类的概述 Java中的Arrays类位于java.util包中,提供了一系列静态方法用于操作数组(如排序、搜索、填充、比较等)。这些方法适用于基本类型数组和对象数组。 常用成员方法及代码示例 排序(sort) 对数组进行升序…...
ArcPy扩展模块的使用(3)
管理工程项目 arcpy.mp模块允许用户管理布局、地图、报表、文件夹连接、视图等工程项目。例如,可以更新、修复或替换图层数据源,修改图层的符号系统,甚至自动在线执行共享要托管在组织中的工程项。 以下代码展示了如何更新图层的数据源&…...
