把Socket實體 掛載到全域
為方便梳理,請忽略
typescript,一切盡在注釋中
# main.ts
import {createApp} from 'vue'
import App from './App.vue'
import {socket} from "@/xihu/socket"
import router from "@/xihu/router"
const app = createApp(App);
app.use(router).mount('#root');
// 全域掛載
app.config.globalProperties.$socket = socket;
Socket封裝(斷線重連)
這個WebSocket類封裝了WebSocket的連接、重連、發送資料等方法,
在connect方法中,它會連接WebSocket,并系結相關事件監聽,
在onclose事件中,它會呼叫reconnect方法進行重連,
reconnect方法會在一定時間內重連,并且重連的時間間隔會越來越長,最大重連次數達到設定值后就不再重連,
這樣就實作了一個可以斷線重連的WebSocket連接,
我們可以在vue應用中使用這個類來進行WebSocket通信,并處理可能出現的網路斷開重連情況,
# socket.ts
// @ts-nocheck
export default class Socket {
constructor(url, protocols) {
this.url = url
this.protocols = protocols
this.ws = null
this.reconnectTimeout = 1000
this.maxReconnectTimes = 5
}
connect() {
this.ws = new WebSocket(this.url, this.protocols)
this.ws.onopen = () => {
console.log('WebSocket連接成功')
this.reconnectTimes = 0
}
this.ws.onclose = () => {
console.log('WebSocket斷開連接')
this.reconnect()
}
this.ws.onerror = err => {
console.log('WebSocket連接出錯', err)
}
}
reconnect() {
if (this.reconnectTimes < this.maxReconnectTimes) {
setTimeout(() => {
this.connect()
this.reconnectTimes++
}, this.reconnectTimeout)
this.reconnectTimeout *= 2
} else {
console.log('WebSocket重連超過最大次數,放棄重連')
}
}
// 訊息發送
msg(param) {
if (param === 'heartbeat') {
this.ws.send(param);
} else {
this.ws.send(JSON.stringify(param));
}
}
// 延遲發送
timeout(param) {
setTimeout(() => {
this.msg(param);
}, 2000)
}
send(param) {
if (this.ws.readyState === this.ws.OPEN) {
this.msg(param);
} else if (this.ws.readyState === this.ws.CONNECTING) {
this.timeout(param);
} else {
this.timeout(param);
}
}
}
實體化Socket
通過type關鍵字,分發資料,并且通過pinia(vuex)存盤實時資料
在訊息回呼函式,處理回傳的資料,使用type關鍵字對應各種推送事件,比如:實時設備告警、地圖顯示用戶坐標等等...
// @ts-nocheck
import {createPinia} from 'pinia';
import {useAlarm} from '@/store/alarm';
// 狀態管理
export const pinia = createPinia();
export const store = useAlarm(pinia);
export function wsInit(callback) {
const url = 'ws://api.xx.cn';
const init = new Socket(url);
// 連接 WebSocket
init.connect();
// 監聽 WebSocket
init.ws.onmessage = function (ev) {
if (ev && ev.data && ev.data.indexOf('subscribe') > -1) {
console.log('subscribe->', ev.data);
} else if (ev && ev.data) {
var data = https://www.cnblogs.com/vmto/archive/2023/05/08/eval('(' + ev.data + ')');
callback(data);
}
};
return init;
}
// 訊息回呼
export const socket = wsInit((data) => {
switch (data.type) {
case 1:
store.setType1(data);
break;
case 2:
store.setType2(data.message);
break;
}
});
// 心跳連接
function heartbeat() {
socket.send("heartbeat");
}
// 十分鐘一次 (簡陋心跳,也請忽略吧^_^)
heartbeat();
setInterval(heartbeat, 1000 * 60 * 10);
狀態管理
# alarm.ts
import {defineStore} from 'pinia'
export const useAlarm = defineStore('user', {
state:()=>({
type1:{},
type2:{},
}),
getters:{
getType1: (state) => state.type1,
getType2: (state) => state.type2,
},
actions:{
setType1(payload: any) {
this.type1 = payload;
},
setType2(payload: any) {
this.type2 = payload;
},
},
})
在頁面中,使用資料(pinia)
# home.vue
import { watch, computed, onMounted, getCurrentInstance} from 'vue'
import {useAlarm} from "@/xihu/store/alarm";
const store = useAlarm();
// 還記得全域掛載的`$socket`吧,這樣使用
const ctx: any = getCurrentInstance();
const {$socket} = ctx.appContext.config.globalProperties;
onMounted(() => {
// 串列資料 -- 根據引數 {"cmd":"1"} 實作資料互動
$socket.send({cmd: 1});
// 回傳的資料格式
const type1 = {
type: 1,
message: [
{id: 1, name: '', value: ''},
{id: 2, name: '', value: ''},
],
};
});
const click = ()=>{
// 其他資料 -- 點擊串列的某一項,根據引數 獲取資料
$socket.send({cmd: 2,extras:{id:1}});
// 回傳的資料格式
const type2 = {
type: 2,
message: {
id: 1, name: '', value: ''
},
};
}
// 這里監聽的資料,是由[訊息回呼]分發的
// 第一種 監聽方式:
watch(() => store.type1, ({message}: any) => {
console.log('/watch/', message);
}, {deep: true});
// 第二種 監聽方式:
store.$subscribe(({events}: any, state) => {
if (events.key === 'type1') {
console.log('/$subscribe/', state.type1);
}
});
大多數情況,資料是后臺主動推送的,比如:告警資料,這也是使用websocket的主要原因
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/551961.html
標籤:其他
上一篇:在JS中如何判斷兩個物件是否相等
下一篇:返回列表
