当前位置:   article > 正文

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

uniapp socket

概要

前端小伙伴使用uni-app开发长连接通信的时候都会有以下疑问

  • 在网上搜到的封装socket都没讲怎么全局公用一个呢?
  • 同一个 子协议或者我我们叫type类型型我想在两个页面都接受使用怎么做呢?

目前能搜到的socket 封装好像都没讲清楚这个东西,或者压根没考虑
下面给大家详细介绍下我封装的方法 大家拿去就可以用。代码在最后了

初始化 创建连接

  • 在合适的场景下创建 Socket 连接
  • 初始化后所有页面均可使用
import socket from "@/components/lvSocket.js"
onLoad(()=>{ // 假设在onLoad周期需要初始化
	socket.connect();// 初始化 全局只需初始化一次
})
onUnload(()=>{
	socket.clearClose();// 关闭长连接根据需要使用
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

接收事件

注意 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);// 清除某个类型中某个回调
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

示例

在两个页面 接受同一个类型 也是互不影响的。 清除的时候别误删了其他事件哦

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');// 清除某个类型所有回调
	})
	
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186

自定义修改说明

  • 后端参数
    代码开头有提到默认后端给到的数据为
    { 
    	type:'msglist',// 你和后端定义的数据type类型
    	"data":{
    		"key":"value",// 这个type类型对应的数据
    		...
    	}
    }
    如果数据有修改。修改_onMessage函数修改传入你们定义的数据即可
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 心跳
    修改代码中_heartbeat函数 修改心跳内容和心跳间隔时间即可
    
    • 1
  • 重连
    默认最多重连1010次都失败就不会重新连接了
    默认重连间隔时间5秒
    只有连接失败 或者服务报错才会重新连接  我们手动关闭连接是不会重新连接的放心使用
    修改_reconnect函数中的10 为你想要的重连次数
    修改_reconnect函数中的5000 为你想要的重连间隔时间
    
    • 1
    • 2
    • 3
    • 4
    • 5

小结

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/318466
推荐阅读
相关标签
  

闽ICP备14008679号