前言
最近有需求要做一個簡單業(yè)務的 APP 應用巴碗,簡單考慮選用 uniapp + uview + vue2.x 方案,因為還有web端頁面也需要用到 WebSocket 扣癣,簡單封裝了一個適應 web 端的工具惰帽,剛開始直接把 web 端的那套代碼拿過來用,跑 H5 模式調試在瀏覽器沒有父虑,打包之后問題就出來了该酗,不支持 WebSocket,當時心里咯噔一下士嚎,想著這下完了呜魄。
冷靜下來,百度查一下莱衩,原來 uniapp 基于 ECMAScript 擴展了 uni 對象爵嗅,非 H5 端不支持 window、document笨蚁、navigator 等瀏覽器專用對象睹晒。uniapp 也實現了 WebSocket ,只是 API 在 uni 對象下括细。
uni.connectSocket
相關 API 可以直接使用伪很,不過 APP 端所有 vue 頁面只能使用一個 websocket 連接。
既然有 API 那就好辦了奋单,參考 H5 的封裝改改锉试。找了好久,能參考并且比較好的文章不多览濒,那咱也寫一段吧呆盖。
參考文章
需求目標
使用 ES6 語法封裝一個公用的 WebSocket 類,供組件使用贷笛。使用類封裝沒試過是否可以創(chuàng)建多個 WebSocket 連接应又,不過 Web 端按照這種方式封裝是可以創(chuàng)建多個連接。
實現過程
定義
在 utils 目錄昨忆,新建一個 websocket.js 文件丁频,定義 WebSocket Class,仔細查看 uniapp 文檔邑贴,調用 uni.connectSocket
接口可以返回一個 SocketTask 對象,有了這個對象之后叔磷,剩下的就是 web 端的差不多了拢驾,對象里面支持斷開自動重連。
如果需要設置重連延遲時間和重連次數可自行擴展屬性改基,目前是寫死在代碼中繁疤。
注意點:
使用 SocketTask
對象,調用存在時序問題,SocketTask.onOpen 要在 uni.connectSocket
回調調用稠腊,不然回調里的內容不會返回躁染。
調用
// index.vue
<script>
import WS from "@/utils/websocket.js"
export default {
//...
data() {
return {
ws: null
}
},
onLoad() {
this.ws && this.ws.closeSocket();
this.ws = new WS(`${process.env.VUE_APP_WS_API}/ws/xxx`)
// 發(fā)送數據
// this.ws.webSocketSendMsg('發(fā)送信息')
this.ws.getWebSocketMsg(data => {
const dataJson = data;
console.log('data', dataJson);
if(typeof(dataJson) == "object") {
console.log("wsObject", dataJson);
}else {
console.log(dataJson);
}
});
},
beforeDestroy() {
this.ws && this.ws.closeSocket();
},
//...
}
</script>
主要代碼
因為 WebSocket 接收的可能是字符串或對象,又封裝了一個類型判斷函數
// @/utils/utils.js
// ...
// 判斷字符串是否為JSON格式
export function isJSON(str) {
if (typeof str == 'string') {
try {
var obj = JSON.parse(str);
if (typeof obj == 'object' && obj) {
return true;
} else {
return false;
}
} catch (e) {
// console.log('error:'+str+'!!!'+e);
return false;
}
}
// console.log('It is not a string!')
}
// ...
websocket.js 完整代碼
// @/utils/websocket.js
import { isJSON } from "@/utils/utils"
class WebSocketClass {
constructor(url) {
this.lockReconnect = false; // 是否開始重連
this.wsUrl = ""; // ws 地址
this.globalCallback = null; // 回調方法
this.userClose = false; // 是否主動關閉
this.createWebSocket(url);
}
createWebSocket(url) {
if (typeof (uni.connectSocket) === 'undefined') {
this.writeToScreen("您的瀏覽器不支持WebSocket架忌,無法獲取數據");
return false
}
this.wsUrl = url;
try {
// 創(chuàng)建一個this.ws對象吞彤,發(fā)送、接收叹放、關閉socket都由這個對象操作
let that = this
this.ws = uni.connectSocket({
url: this.wsUrl,
success(data) {
console.log("websocket連接成功");
that.initEventHandle();
},
});
} catch (e) {
this.reconnect(url);
}
}
// 初始化
initEventHandle() {
// 監(jiān)聽WebSocket連接打開成功
this.ws.onOpen(res => {
console.log('WebSocket連接打開');
});
// 連接關閉后的回調函數
this.ws.onClose(() => {
if (!this.userClose) {
this.reconnect(this.wsUrl); //重連
}
});
// 報錯時的回調函數
this.ws.onError(() => {
if (!this.userClose) {
this.reconnect(this.wsUrl); //重連
}
});
// 收到服務器數據后的回調函數
this.ws.onMessage(event => {
if(isJSON(event.data)) {
const jsonobject = JSON.parse(event.data)
this.globalCallback(jsonobject)
}else {
this.globalCallback(event.data)
}
});
}
// 關閉ws連接回調
reconnect(url) {
if (this.lockReconnect) return;
this.ws.close();
this.lockReconnect = true; // 關閉重連饰恕,沒連接上會一直重連,設置延遲避免請求過多
setTimeout(() => {
this.createWebSocket(url);
this.lockReconnect = false;
}, 30000); // 重連延遲時間
}
// 發(fā)送信息方法
webSocketSendMsg(msg) {
this.ws && this.ws.send({
data: msg,
success() {
console.log("消息發(fā)送成功");
},
fail(err) {
console.log("關閉失敗", err)
}
});
}
// 獲取ws返回的數據方法
getWebSocketMsg(callback) {
this.globalCallback = callback
}
// 關閉ws方法
closeSocket() {
if (this.ws) {
this.userClose = true;
this.ws.close({
success(res) {
console.log("關閉成功", res)
},
fail(err) {
console.log("關閉失敗", err)
}
});
}
}
writeToScreen(massage) {
console.log(massage);
}
}
export default WebSocketClass;
實現結果
實測可用