行业知识
uni-app vue3 封装socket 兼容微信小程序 钉钉小程序 H5 App 全局唯一
2026-11-08 03:42:26
来源:互联网转载
文章目录
- 概要
- 初始化 创建连接
- 接收事件
- 示例
- js代码
- 自定义修改说明
- 小���
概要
前端小伙伴使用uni-app开发长连接通信的时候都会有以下疑问
()- 在网上搜到的封装socket都没讲怎么全局公用一个呢?
- 同一个 子协议或者我我们叫type类型型我想在两个页面都接受使用怎么做呢?
目前能搜到的socket 封装好像都没讲清楚这个东西,或者压根没考虑
下面给大家详细介绍下我封装的方法 大家拿去就可以用。代码在最后了
()初始化 创建连接
- 在合适的场景下创建 Socket 连接
- 初始化后所有页面均可使用
import socket from "@/components/lvSocket.js"onLoad(()=>{ // 假设在onLoad周期需要初始化socket.connect();// 初始化 全局只需初始化一次})onUnload(()=>{socket.clearClose();// 关闭长连接根据需要使用})接收事件
注意 type等于all时接收所有类型参数
import socket from "@/components/lvSocket.js"onLoad(()=>{ // 假设在onLoad周期需要初始化// 发送消息socket.send({"type": "msgList",// 传输类型 "payLoad": {传输内容}});socket.on("hei",shjian);// type=hei:接受hei类型参数socket.on("hei",()=>{console.log('hei收到了')});// type=hei:接受hei类型参数socket.on("heier",()=>{console.log('er收到了')});// type=heier:接受hei类型参数socket.on("all",jieshouAll);// type=all:接受所有参数 all为type类型关键字})const shjian = (meg)=>{console.log('页面收到hei数据',meg)}const jieshouAll = (meg)=>{console.log('服务端返回的所有数据都能接收到',meg)}// 页面卸载清除事件回调onUnload(()=>{socket.off();// 清空所有回调socket.off('hei');// 清除某个类型所有回调socket.off('hei',jieshou);// 清除某个类型中某个回调})示例
在两个页面 接受同一个类型 也是互不影响的。 清除的时候别误删了其他事件哦
import socket from "@/components/lvSocket.js"// index 页面onLoad(()=>{socket.connect();// 初始化 全局只需初始化一次socket.on("hei",jieshou);// type=hei:接受hei类型参数socket.on("all",jieshouAll);// type=all:接受所有参数 all为type类型关键字})const jieshou = (meg)=>{console.log('页面收到数据',meg)socket.send({type:"pingaaaaa"});// 发送消息}const jieshouAll = (meg)=>{console.log('服务端返回的所有数据都能接收到',meg)}// 页面卸载清除事件回调onUnload(()=>{socket.off();// 清空所有回调socket.off('hei');// 清除某个类型所有回调socket.off('hei',jieshou);// 清除某个类型中某个回调socket.clearClose();// 关闭长连接根据需要使用})// home页面onLoad(()=>{socket.on("bookList",getBookList);// 接受参数})const getBookList = (meg)=>{console.log('页面收到数据',meg)}// 页面卸载清除事件回调onUnload(()=>{socket.off('bookList');// 清除某个类型所有回调})js代码
在 src/components 路径下创建 lvSocket.js 粘贴如下代码到文件中
vue2使用请注意this指向问题
/*假设后端响应数据类型是这样的{ type:'msglist',"payload":{... 数据在这里}}*//**** @description: WebSocket 单例模式* @author: lvhao*/class Socket {constructor() {this.socket = null;// socket实例this.isConnect = false;// 是否连接成功this.reconnectCount = 0;// 重连接次数this.reconnectTimer = null;// 重连定时器this.url = `ws://192.168.28.38:3000`this.isHandClose = false;// 是否是手动关闭// 心跳定时器this.heartbeatInterval = null;// 收集事件绑定类型this._map = new Map();// 收集未连接成功要发送的消息this._sendArr = [];}// 连接connect() {if (this.socket) return;// 正在连接const Token = uni.getStorageSync('Token');this.socket = uni.connectSocket({url:this.url,header: {"wsToken": `Bearer ${Token}`,},complete: ()=> {},multiple:true,})// 连接成功this.socket.onOpen(()=>{console.log("连接成功")this._onOpen();})// Socket 连接关闭事件this.socket.onClose(() => {console.log("连接关闭了")this._onClose();});// 监听 Socket 错误事件this.socket.onError((err) => {console.log("Socket报错了",err)this._onError();});// 监听 WebSocket 接受到服务器的消息事件this.socket.onMessage((meg)=>{this._onMessage(meg)});}// 连接成功 重置参数_onOpen() {this.isConnect = true;// 是否连接成功this.reconnectCount = 0;// 重置重连次数clearTimeout(this.reconnectTimer);// 清空重连定时器this.isHandClose = false;// 是否是手动关闭this._heartbeat();// 开启心跳// 未发送的消息全部发送this._sendArr.forEach(item=>{this.send(item);// 发送消息})this._sendArr = [];}// 监听 WebSocket 连接关闭事件_onClose() {this.socket = null;// 清空soketthis.isConnect = false;// 是否连接成功this._clearHeartbeat();// 关闭心跳this._reconnect();// 重新连接}// 监听 WebSocket 错误事件_onError() {}// 监听 WebSocket 接受到服务器的消息事件_onMessage(meg) {let data = JSON.parse(meg.data);// 收到的数据let receiveType = data.type;// 收到的type类型// 触发对应type类型事件 接受type为all时所有事件都会触发for (let entry of this._map.entries()) {if(entry[1] === receiveType || entry[1] === 'all' ){entry[0](data.payLoad)}}}// 自动重连_reconnect() {if(this.isHandClose)return;// 手动关闭不重连if(this.socket)return;// 正在连接不处理if (this.reconnectCount {console.log(`WebSocket 重连中,第 ${this.reconnectCount} 次尝试...`);this.connect();//连接}, 5000);} else {console.log('WebSocket 重连失败!');}}// 开启心跳_heartbeat(){this._clearHeartbeat();// 关闭心跳// 心跳10000ms发送一次this.heartbeatInterval = setInterval(()=>{this.send({type:'ping', "payLoad": {"ts": new Date().getTime()}})//心跳内容},10000)}// 关闭心跳_clearHeartbeat(){clearInterval(this.heartbeatInterval)}// 发送消息send(data) {// 当前未连接记录内容 队列中没有才放入 心跳除外if(!this.isConnect && data.type !== "ping" ){const hasEqualItem = this._sendArr.some(item => JSON.stringify(item) == JSON.stringify(data));if (!hasEqualItem) {this._sendArr.push(data);}return;}this.socket.send({'data':JSON.stringify(data)});}// 接受信息 type 类型 fn 回调函数on(type,fn=()=>{}){this._map.set(fn,type);}// 关闭接受参数off(type,fn){// 关闭参数if(arguments.length === 0){// 清除全部this._map.clear();}else if(arguments.length === 1){// 清除某个事件类型整体this._map.forEach((value, key) => {if (value === type) {this._map.delete(key);}});}else{// 清除某个事件类型中某个回调if(this._map.get(fn) === type){this._map.delete(fn)}}}// 关闭clearClose() {this.isHandClose = true;// 手动关闭clearTimeout(this.reconnectTimer);// 清空重连定时器if(this.socket && "close" in this.socket){this.socket.close(); // 关闭soket}}}export default new Socket()自定义修改说明
- 后端参数
代码开头有提到默认后端给到的数据为{ type:'msglist',// 你和后端定义的数据type类型"data":{"key":"value",// 这个type类型对应的数据...}}如果数据有修改。修改_onMessage函数修改传入你们定义的数据即可 - 心跳
修改代码中_heartbeat函数 修改心跳内容和心跳间隔时间即可
- 重连
默认最多重连10次 10次都失败就不会重新连接了默认重连间隔时间5秒只有连接失败 或者服务报错才会重新连接 我们手动关闭连接是不会重新连接的放心使用修改_reconnect函数中的10 为你想要的重连次数修改_reconnect函数中的5000 为你想要的重连间隔时间
小结
可以根据自己的需要对其进行魔改。 不懂的地方可以联系我帮大家答疑。v:H1274714546
欢迎有更好方案的小伙伴评论。分享转载,请注明来源哦~
- 后端参数