uni-app vue3 封装socket 兼容微信小程序 钉钉小程序 H5 App 全局唯一

概要

前端小伙伴使用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;// 清空soket
		this.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 < 10) {
			this.reconnectCount++;
			this.reconnectTimer = setTimeout(() => {
				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函数 修改心跳内容和心跳间隔时间即可
    
  • 重连
    默认最多重连1010次都失败就不会重新连接了
    默认重连间隔时间5秒
    只有连接失败 或者服务报错才会重新连接  我们手动关闭连接是不会重新连接的放心使用
    修改_reconnect函数中的10 为你想要的重连次数
    修改_reconnect函数中的5000 为你想要的重连间隔时间
    

小结

可以根据自己的需要对其进行魔改。 不懂的地方可以联系我帮大家答疑。v:H1274714546
欢迎有更好方案的小伙伴评论。分享转载,请注明来源哦~

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值