// websocket.js // 封装一个兼容多端的 uniapp WebSocket 管理类,支持自动重连与心跳机制,便于在uni-app项目中统一管理WebSocket连接 class UniWebSocket { /** * 构造函数,初始化WebSocket管理器 * @param {string} url - WebSocket服务器地址 * @param {object} options - 可选配置项,如最大重连次数、心跳间隔等 */ constructor(url, options = {}) { this.url = url; // WebSocket服务器地址 this.options = options; // 连接配置参数 this.socketTask = null; // uni.connectSocket返回的socket任务对象 this.isConnected = false; // 当前连接状态 this.reconnectCount = 0; // 当前已重连次数 this.maxReconnect = options.maxReconnect || 5; // 最大重连次数,默认5次 this.heartbeatInterval = options.heartbeatInterval || 30000; // 心跳包发送间隔,默认30秒 this.heartbeatTimer = null; // 心跳定时器 this.eventListeners = { open: [], // 连接打开事件监听器 message: [], // 消息接收事件监听器 error: [], // 错误事件监听器 close: [] // 关闭事件监听器 }; this.manualClose = false; // 是否为手动关闭连接 } /** * 建立WebSocket连接 * 若已连接则不重复连接 */ connect() { if (this.isConnected) return; this.manualClose = false; this.socketTask = uni.connectSocket({ url: this.url, ...this.options }); this._initEvent(); // 初始化事件监听 } /** * 初始化WebSocket事件监听(open、message、error、close) * 绑定到socketTask对象 * @private */ _initEvent() { // 连接成功事件 this.socketTask.onOpen = (res) => { this.isConnected = true; this.reconnectCount = 0; this._emit('open', res); this._startHeartbeat(); // 启动心跳 }; // 接收到消息事件 this.socketTask.onMessage = (res) => { this._emit('message', res); this._startHeartbeat(); // 收到消息后重置心跳 }; // 连接错误事件 this.socketTask.onError = (err) => { this._emit('error', err); this._reconnect(); // 尝试重连 }; // 连接关闭事件 this.socketTask.onClose = (res) => { this.isConnected = false; this._emit('close', res); this._stopHeartbeat(); // 停止心跳 if (!this.manualClose) { this._reconnect(); // 非手动关闭时自动重连 } }; } /** * 发送消息到WebSocket服务器 * @param {string|object} data - 要发送的数据,支持字符串或对象 * @returns {Promise} - 发送成功/失败的Promise */ send(data) { return new Promise((resolve, reject) => { if (!this.isConnected) { reject('WebSocket 未连接'); return; } this.socketTask.send({ data: typeof data === 'string' ? data : JSON.stringify(data), success: resolve, fail: reject }); }); } /** * 主动关闭WebSocket连接 * @param {number} code - 关闭码,默认1000 * @param {string} reason - 关闭原因 */ close(code = 1000, reason = '') { this.manualClose = true; if (this.socketTask) { this.socketTask.close({ code, reason }); } this._stopHeartbeat(); } /** * 注册事件监听器 * @param {string} event - 事件名(open/message/error/close) * @param {function} callback - 回调函数 */ on(event, callback) { if (this.eventListeners[event]) { this.eventListeners[event].push(callback); } } /** * 移除事件监听器 * @param {string} event - 事件名 * @param {function} callback - 需移除的回调函数 */ off(event, callback) { if (this.eventListeners[event]) { this.eventListeners[event] = this.eventListeners[event].filter(fn => fn !== callback); } } /** * 触发事件,调用所有注册的监听器 * @param {string} event - 事件名 * @param {any} data - 事件数据 * @private */ _emit(event, data) { if (this.eventListeners[event]) { this.eventListeners[event].forEach(fn => fn(data)); } } /** * 自动重连逻辑,递增重连次数,超出最大次数则停止 * @private */ _reconnect() { if (this.reconnectCount < this.maxReconnect) { this.reconnectCount++; setTimeout(() => { this.connect(); }, 1000 * this.reconnectCount); // 重连间隔递增 } } /** * 启动心跳机制,定时发送ping包保持连接活跃 * @private */ _startHeartbeat() { this._stopHeartbeat(); if (this.heartbeatInterval > 0) { this.heartbeatTimer = setInterval(() => { if (this.isConnected) { this.send('ping').catch(() => {}); } }, this.heartbeatInterval); } } /** * 停止心跳机制 * @private */ _stopHeartbeat() { if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); this.heartbeatTimer = null; } } } export default UniWebSocket;