WebSocket 的封装

news/2024/9/20 2:05:56/ 标签: 前端, vue.js, javascript, 开发语言, websocket

websocket 具体内容参考了 原文

import {ref, onUnmounted} from 'vue';
import dayjs from "dayjs";class Socket {url;ws = null;opts;reconnectAttempts = 0;listeners = {};heartbeatInterval = null;constructor(url, opts = {}) {this.url = url;this.opts = {// 心跳检测heartbeatInterval: 30000,// 重新连接时间间隔reconnectInterval: 5000,// 重连的次数maxReconnectAttempts: 3,...opts};this.init();}init() {this.ws = new WebSocket(this.url);this.ws.onopen = this.onOpen.bind(this);this.ws.onmessage = this.onMessage.bind(this);this.ws.onerror = this.onError.bind(this);this.ws.onclose = this.onClose.bind(this);}onOpen(event) {if (event) {console.log(`%c websocket 已建立连接 ${dayjs(new Date()).format("HH:mm:ss")}`, 'color: green');this.reconnectAttempts = 0;this.startHeartbeat();this.emit('open', event);}}onMessage(event) {this.emit('message', event.data);}onError(event) {console.error('WebSocket error:', event);this.emit('error', event);}onClose(event) {console.log(`%c websocket 已断开连接 ${dayjs(new Date()).format("HH:mm:ss")}`, 'color: red');this.stopHeartbeat();this.emit('close', event);if (!window.wsIsClosed) {if (this.reconnectAttempts < this.opts.maxReconnectAttempts) {setTimeout(() => {this.reconnectAttempts++;this.init();}, this.opts.reconnectInterval);}}}startHeartbeat() {if (!this.opts.heartbeatInterval) return;this.heartbeatInterval = window.setInterval(() => {if (this.ws?.readyState === WebSocket.OPEN) {console.log(`%c ❤ 检测 ${dayjs(new Date()).format("HH:mm:ss")}`, 'color: yellow');this.ws.send('ping');}}, this.opts.heartbeatInterval);}stopHeartbeat() {if (this.heartbeatInterval) {clearInterval(this.heartbeatInterval);this.heartbeatInterval = null;}}send(data) {if (this.ws?.readyState === WebSocket.OPEN) {this.ws.send(data);} else {console.error('WebSocket is not open. Cannot send:', data);}}on(event, callback) {if (!this.listeners[event]) {this.listeners[event] = [];}this.listeners[event].push(callback);}off(event) {if (this.listeners[event]) {delete this.listeners[event];}}emit(event, data) {this.listeners[event]?.forEach(callback => callback(data));}
}export function useSocket(url, opts) {const socket = new Socket(url, opts);onUnmounted(() => {socket.off('open');socket.off('message');socket.off('error');socket.off('close');});return {socket,send: socket.send.bind(socket),on: socket.on.bind(socket),off: socket.off.bind(socket)};
}

然后为了方便在 项目中进行使用,我们自定义一些 Hooks

import {useSocket} from "@/utils/websocket";
import {showNotify} from "@/utils/notifies";export function useWebSocket(userId, store) {const startWS = () => {const {socket,on, off} = useSocket(`${process.env.VUE_APP_BASE_API.replace("https://", "wss://").replace("http://", "ws://")}/websocket/${userId}`);window.socketTarget = socketwindow.wsIsClosed = false;let messageQueue = []; // 用于存储消息的队列on('message', data => {if (data !== "ping") {const targetObjData = JSON.parse(data);if (targetObjData["msg_front_from"] && targetObjData) {// 邮件消息messageQueue.push(targetObjData); // 将消息添加到队列中} else {// 通知消息store.commit("message/setNewData", data);store.dispatch("message/getUnReadMessageListApisDefault", {pageNo: 1, pageSize: 999})}}});// 在 3 秒后处理消息队列并触发 showNotifylet timer = null;const processMessageQueue = () => {if (messageQueue.length > 0) {setTimeout(() => {store.commit("message/setEmailData", messageQueue);showNotify(messageQueue.length, messageQueue[0], () => {localStorage.setItem('activeMenu', '/email/inbox')router.push('/email/inbox')});messageQueue = []; // 清空消息队列clearInterval(timer)}, 3000);}};timer = setInterval(processMessageQueue, 3000); // 每 3 秒处理一次消息队列};const stopWS = () => {if (window.socketTarget) {window.socketTarget.ws.close();window.wsIsClosed = true;}}return {startWS,stopWS,};
}

showNotify 的自定义

import {ElNotification} from "element-plus";export function showNotify(messageNumber, item, fun) {if (item) {const {msg_front_from, msgTxt} = itemconst replaceEmail = msg_front_from.replace(/^<|>$/g, "")ElNotification({position: 'bottom-right',duration: 3000,dangerouslyUseHTMLString: true,onClick() {fun()},message: `<div class="notify_box"><div class="notify_left"><div class="notify_inner" style="background-color:#5272e5;padding: 0px 14px;border-radius: 8px"><svg t="1708593116687" className="icon" viewBox="0 0 1024 1024" version="1.1"xmlns="http://www.w3.org/2000/svg" p-id="5124" width="32" height="32"><pathd="M891.904 145.92H128.512c-55.808 0-101.376 45.568-101.376 101.376v573.952c0 55.808 45.568 101.376 101.376 101.376h763.392c55.808 0 101.376-45.568 101.376-101.376V247.296c0-55.808-45.568-101.376-101.376-101.376z m-10.24 68.096l-352.768 285.184c-1.024 0.512-2.048 1.536-2.56 2.56-8.704 8.704-23.04 8.704-31.744 0l-2.56-2.56-352.768-285.184h742.4z m10.24 640.512H128.512c-18.432 0-32.768-14.848-32.768-32.768V266.752l351.744 284.672c17.408 16.896 39.936 25.088 62.464 25.088 22.528 0 45.056-8.192 62.464-25.088l351.744-284.672v554.496c0.512 18.432-13.824 33.28-32.256 33.28z"p-id="5125" fill="#fff"></path></svg></div><div class="badge">${messageNumber}</div></div><div class="notify_right" style="width: 200px"><div><span class="userInfo">${replaceEmail}</span></div><div style="width: 185px;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;">${msgTxt}</div></div></div>`})}
}

Hooks 的使用

import {useWebSocket} from "@/Hooks";
const {startWS, stopWS} = useWebSocket(userId, store);//在合适的地方调用 startWS() 或 stopWS() 即可

http://www.ppmy.cn/news/1451984.html

相关文章

Java image-processing 包依赖错误

错误的信息为&#xff1a; [ERROR] Failed to execute goal on project image-processing: Could not resolve dependencies for project com.ossez:image-processing:jar:0.0.2-SNAPSHOT: Failed to collect dependencies at org.openimaj:core-image:jar:1.3.10 -> org.op…

机器学习每周挑战——二手车车辆信息交易售价数据

这是数据集的截图 目录 背景描述 数据说明 车型对照&#xff1a; 燃料类型对照&#xff1a; 老规矩&#xff0c;第一步先导入用到的库 第二步&#xff0c;读入数据&#xff1a; 第三步&#xff0c;数据预处理 第四步&#xff1a;对数据的分析 第五步&#xff1a;模型建…

ES集群分布式查询原理

集群分布式查询 elasticsearch的查询分成两个阶段&#xff1a; scatter phase&#xff1a;分散阶段&#xff0c;coordinating node会把请求分发到每一个分片gather phase&#xff1a;聚集阶段&#xff0c;coordinating node汇总data node的搜索结果&#xff0c;并处理为最终结…

设计模式的原则与分类

一、设计模式的原则 1、单一职责原则 一个类只需要负责一种职责即可&#xff0c;一个类发生变化的原因&#xff0c;必然是所负责的职责发生变化 2、接口隔离原则 单一职责原则是接口隔离原则的基础&#xff0c;单一职责原则注重职责的划分&#xff0c;从职责角度进行类和接口…

使用docker创建rocketMQ主从结构,使用

1、 创建目录 mkdir -p /docker/rocketmq/logs/nameserver-a mkdir -p /docker/rocketmq/logs/nameserver-b mkdir -p /docker/rocketmq/logs/broker-a mkdir -p /docker/rocketmq/logs/broker-b mkdir -p /docker/rocketmq/store/broker-a mkdir -p /docker/rocketmq/store/b…

【数据结构与算法】力扣 347. 前 K 个高频元素

题目描述 给你一个整数数组 nums 和一个整数 k &#xff0c;请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 示例 1: 输入: nums [1,1,1,2,2,3], k 2 输出: [1,2]示例 2: 输入: nums [1], k 1 输出: [1]提示&#xff1a; 1 < nums.length < …

KIE关键信息抽取——SDMG-R

https://arxiv.org/pdf/2103.14470https://arxiv.org/pdf/2103.14470 1.概述 背景:传统的关键信息提取方法依赖于模板匹配,这使它们难以泛化到未见过的模板,且对文本识别错误不够鲁棒。SDMG-R方法:提出一种端到端的双模态图推理方法,通过构建双模态图(视觉和文本特征),…

多级留言/评论的功能实现——SpringBoot3后端篇

目录 功能描述数据库表设计后端接口设计实体类entity 完整实体类dto 封装请求数据dto 封装分页请求数据vo 请求返回数据 Controller控制层Service层接口实现类 Mapper层Mybatis 操作数据库 补充&#xff1a;返回的数据结构自动创建实体类 最近毕设做完了&#xff0c;开始来梳理…

【CTF MISC】XCTF GFSJ0512 give_you_flag Writeup(图像处理+QR Code识别)

give_you_flag 菜狗找到了文件中的彩蛋很开心&#xff0c;给菜猫发了个表情包 解法 图片的最后一帧好像闪过了什么东西。 用 Photoshop 打开&#xff0c;检查时间轴。 找到一张二维码&#xff0c;但是缺了三个角&#xff08;定位图案&#xff09;&#xff0c;无法识别。 找一…

《QT实用小工具·四十九》QT开发的轮播图

1、概述 源码放在文章末尾 该项目实现了界面轮播图的效果&#xff0c;包含如下特点&#xff1a; 左右轮播 鼠标悬浮切换&#xff0c;无需点击 自动定时轮播 自动裁剪和缩放不同尺寸图片 任意添加、插入、删除 单击事件&#xff0c;支持索引和自定义文本 界面美观&#xff0c;圆…

matlab绘制热点图

在MATLAB中&#xff0c;通常使用imagesc、pcolor、heatmap&#xff08;需要Statistics and Machine Learning Toolbox&#xff09;等函数来绘制热点图&#xff08;也称为热力图&#xff09;。热点图通常用于可视化矩阵数据&#xff0c;其中每个单元格的颜色表示矩阵中相应元素的…

前端代码优化-switch的使用

当我们需要根据这段的不同而展示不同的文字时&#xff0c;下面的写法太过于麻烦&#xff0c;同样的代码写了很多遍&#xff0c;这个时候就需要优化&#xff0c;如果判断的东西更多&#xff0c;总不能一个一个再写 判断 <div class"alarm-detail-item" v-if"…

【Unity】Mathf

【Unity】Mathf 1.Math与Mathf 推荐使用Mathf Math是C#中封装好的用于数学计算的工具 类&#xff0c;Math位于System命名空间中Mathf是Unity中封装好的用于数学计算的工具 结构体&#xff0c;Mathf位于UnityEngine命名空间中Mathf比Math方法多&#xff0c;不仅包含Math中的方…

【基础算法总结】滑动窗口一

滑动窗口 1.长度最小的字数组2.无重复字符的最长子串3.最大连续1的个数 III4.将 x 减到 0 的最小操作数 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&…

贪心算法基础题(第三十三天)

455. 分发饼干 题目 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#xff0c;都有一个胃口值 g[i]&#xff0c;这是能让孩子们满足胃口的饼干的最小尺寸&#xff1b;并且每块饼干 j&#xf…

Adobe Firefly 3.0 AI 图像生成器来了

Adobe 发布其 Midjourney 和 Dall-E 3 竞争对手Firefly 2.0已经半年了。几天前&#xff0c;他们发布了Firefly 3.0&#xff08;目前处于测试阶段&#xff09;&#xff0c;这是他们最新的文本到图像人工智能工具&#xff0c;其中包含一些非常酷的更新。在我们深入了解细节之前&a…

json转excel

前面有介绍过excel文件转换成json文件的方法&#xff0c;那json文件转excel文件呢&#xff1f;如果json文件里数据格式都是统一的话&#xff0c;那么也比较容易就转。 我们假设json文件中是一个json数组&#xff0c;每条json数据的属性字段都一样&#xff0c;手写一段node.js例…

聊聊 ASP.NET Core 中间件(一):一个简单的中间件例子

前言&#xff1a;什么是中间件 服务器在收到 HTTP 请求后会对用户的请求进行一系列的处理&#xff0c;比如检查请求的身份验证信息、处理请求报文头、检查是否存在对应的服务器端响应缓存、找到和请求对应的控制器类中的操作方法等&#xff0c;当控制器类中的操作方法执行完成…

十大排序算法之——堆排序算法(Java实现)及思路讲解

堆排序是一种非常有效的排序算法&#xff0c;它利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构&#xff0c;并同时满足堆积的性质&#xff1a;即子节点的键值或索引总是小于&#xff08;或者大于&#xff09;它的父节点。堆排序可以分为两个主要部分&a…

手搓堆(C语言)

Heap.h #pragma once#include <stdio.h> #include <stdlib.h> #include <assert.h> #include <stdbool.h> #include <string.h> typedef int HPDataType; typedef struct Heap {HPDataType* a;int size;int capacity; }Heap;//初始化 void Heap…