如何使用vue3簡單實(shí)現(xiàn)WebSocket通信
前言
WebSocket是一種在客戶端和服務(wù)器之間進(jìn)行雙向通信的網(wǎng)絡(luò)協(xié)議。它通過建立持久性的、全雙工的連接,允許服務(wù)器主動向客戶端發(fā)送數(shù)據(jù),而不需要客戶端顯式地發(fā)送請求。
關(guān)于WebSocket通信的簡單介紹:
- 握手階段:在建立WebSocket連接之前,客戶端需要發(fā)送一個(gè)HTTP請求到服務(wù)器,請求升級為WebSocket協(xié)議。這個(gè)過程稱為握手(Handshake)。如果服務(wù)器支持WebSocket協(xié)議,它將返回帶有特定標(biāo)頭的HTTP響應(yīng),表示握手成功。
- 建立連接:客戶端收到服務(wù)器的握手響應(yīng)后,會重新建立連接。此時(shí),連接將從HTTP協(xié)議切換到WebSocket協(xié)議,并保持打開狀態(tài)。這樣就建立了可持續(xù)的雙向通信通道。
- 數(shù)據(jù)傳輸:一旦WebSocket連接建立,客戶端和服務(wù)器可以開始互相發(fā)送消息??蛻舳撕头?wù)器都可以通過發(fā)送文本或二進(jìn)制數(shù)據(jù)來通信。消息可以是簡單的字符串,也可以是復(fù)雜的數(shù)據(jù)結(jié)構(gòu),如JSON對象等。
- 斷開連接:當(dāng)需要關(guān)閉WebSocket連接時(shí),客戶端或服務(wù)器可以主動發(fā)送一個(gè)關(guān)閉幀來斷開連接。收到關(guān)閉幀的一方會結(jié)束連接并發(fā)送回應(yīng)幀,完成連接的關(guān)閉。
WebSocket通信具有以下特點(diǎn):
- 實(shí)時(shí)性:由于WebSocket使用長連接,可以實(shí)時(shí)地將數(shù)據(jù)推送到客戶端,而不需要顯式地發(fā)送請求。這使得它非常適合需要快速、實(shí)時(shí)響應(yīng)的應(yīng)用程序。
- 雙向通信:WebSocket允許客戶端和服務(wù)器之間雙向傳輸消息。這意味著服務(wù)器可以主動向客戶端推送數(shù)據(jù),而不僅限于響應(yīng)客戶端的請求。
- 較低的開銷:相比于傳統(tǒng)的輪詢方式(每隔一段時(shí)間發(fā)送請求),WebSocket連接具有較低的開銷。一旦建立連接,它只需要發(fā)送少量的數(shù)據(jù)頭部信息,并且在保持連接時(shí)可以重復(fù)使用該連接。
- 跨平臺支持:WebSocket協(xié)議是一種標(biāo)準(zhǔn)化的協(xié)議,被廣泛支持和應(yīng)用于不同的平臺和編程語言中。
通過使用WebSocket,開發(fā)人員可以實(shí)現(xiàn)實(shí)時(shí)通信、聊天應(yīng)用、多人游戲、股票行情等需要及時(shí)交互和更新的應(yīng)用程序。
相關(guān)代碼如下:
①創(chuàng)建src/utils/websocket.ts文件
import { ElMessage } from 'element-plus'
import store from '../store'
let websocket: WebSocket | null = null; // 用于存儲實(shí)例化后websocket
let rec: any; // 斷線重連后,延遲5秒重新創(chuàng)建WebSocket連接 rec用來存儲延遲請求的代碼
// 創(chuàng)建websocket
function creatWebSocket(wsUrl: string) {
console.log("websocket==================");
// 判斷當(dāng)前瀏覽器是否支持WebSocket
if ("WebSocket" in window) {
console.log("當(dāng)前瀏覽器支持 WebSocket");
} else if ("MozWebSocket" in window) {
console.log("當(dāng)前瀏覽器支持 MozWebSocket");
} else {
console.log("當(dāng)前瀏覽器不支持 WebSocket");
}
try {
initWebSocket(wsUrl); // 初始化websocket連接
} catch (e) {
console.log("嘗試創(chuàng)建連接失敗");
reConnect(wsUrl); // 如果無法連接上 webSocket 那么重新連接!可能會因?yàn)榉?wù)器重新部署,或者短暫斷網(wǎng)等導(dǎo)致無法創(chuàng)建連接
}
}
// 初始化websocket
function initWebSocket(wsUrl: string) {
websocket = new WebSocket(wsUrl);
console.log("websocket:", websocket);
websocket.onopen = function () {
websocketOpen();
};
// // 接收
websocket.onmessage = function (e: MessageEvent<any>) {
websocketonmessage(e);
};
// 連接發(fā)生錯誤
websocket.onerror = function () {
console.log("WebSocket連接發(fā)生錯誤");
// isConnect = false; // 連接斷開修改標(biāo)識
reConnect(wsUrl); // 連接錯誤 需要重連
};
websocket.onclose = function (e) {
websocketclose(e);
};
}
// 定義重連函數(shù)
let reConnect = (wsUrl: string) => {
console.log("嘗試重新連接");
if (store.state.isConnected) return; // 如果已經(jīng)連上就不在重連了
rec && clearTimeout(rec);
rec = setTimeout(function () {
// 延遲5秒重連 避免過多次過頻繁請求重連
creatWebSocket(wsUrl);
}, 5000);
};
// 創(chuàng)建連接
function websocketOpen() {
console.log("連接成功");
store.dispatch('connect'); // 修改連接狀態(tài)
}
// 數(shù)據(jù)接收
function websocketonmessage(e: MessageEvent<any>) {
console.log("數(shù)據(jù)接收", e.data);
const data = JSON.parse(e.data); // 解析JSON格式的數(shù)據(jù)
// 下面的判斷則是后臺返回的接收到的數(shù)據(jù) 如何處理自己決定
if (data.code === 400) {
console.log("數(shù)據(jù)接收", data.msg);
ElMessage({
showClose: true,
message: data.msg,
type: 'warning',
})
} else if (data.code === 404) {
ElMessage({
showClose: true,
message: data.msg,
type: 'warning',
})
} else if (data.code === 0) {
ElMessage({
showClose: true,
message: "連接成功",
type: 'success',
})
} else if (data.code === 200) {
ElMessage({
showClose: true,
message: data.msg,
type: 'success',
})
// 成功后的相應(yīng)處理 此處成功后播放音樂
const audio = new Audio('./tipMusic.mp3');
audio.play();
} else {
ElMessage({
showClose: true,
message: data.msg,
type: 'error',
})
// 延時(shí)5秒后刷新頁面
setTimeout(() => {
location.reload();
}, 1000);
}
// let data = JSON.parse(decodeUnicode(e.data))
}
// 關(guān)閉
function websocketclose(e: any) {
console.log(e);
store.dispatch('disconnect'); // 修改連接狀態(tài)
console.log("connection closed (" + e.code + ")");
}
// 數(shù)據(jù)發(fā)送
function websocketsend(data: any) {
console.log("發(fā)送的數(shù)據(jù)", data, JSON.stringify(data));
if (websocket && store.state.isConnected) { // 檢查連接狀態(tài)
websocket.send(JSON.stringify(data));
} else {
ElMessage({
showClose: true,
message: "請選擇設(shè)備連接",
type: 'error',
})
}
}
// 實(shí)際調(diào)用的方法==============
// 發(fā)送
function sendWebSocket(data: any) {
// 如果未保持連接狀態(tài) 不允許直接發(fā)送消息 提示請選擇連接設(shè)備
if (!store.state.isConnected) {
ElMessage({
showClose: true,
message: "請選擇設(shè)備連接",
type: 'error',
})
} else {
websocketsend(data);
console.log("------------------");
}
}
// 關(guān)閉
let closeWebSocket = () => {
if (websocket) {
websocket.close();
ElMessage({
showClose: true,
message: "設(shè)備已關(guān)閉",
type: 'success',
})
}
};
export {
initWebSocket,
sendWebSocket,
creatWebSocket,
closeWebSocket,
};②全局保存連接狀態(tài)src/store/index.ts
先安裝npm install vuex
import { createStore } from 'vuex'
const store = createStore({
state: {
isConnected: false,//連接狀態(tài)
},
mutations: {
setConnected(state: any, isConnected: boolean) {
state.isConnected = isConnected
},
},
actions: {
connect({ commit }: { commit: any }) {
// 連接成功后,將 isConnected 狀態(tài)設(shè)置為 true
commit('setConnected', true)
},
disconnect({ commit }: { commit: any }) {
// 斷開連接或退出登錄時(shí),將 isConnected 狀態(tài)設(shè)置為 false
commit('setConnected', false)
}
}
})
export default store③頁面連接設(shè)備
<script setup lang="ts">
import { ref ,onMounted} from 'vue'
import { closeWebSocket,initWebSocket } from '../../utils/websocket'
import { useStore } from 'vuex';
const store = useStore()
//連接設(shè)備 (具體路徑和后端規(guī)定)
function connectMsg() {
const toIp = `ws://192.168.50.50:8822/websocket/ipad/${roomId.value}`;
store.dispatch('connect')
initWebSocket(toIp)
}
// 設(shè)備斷開
function closeWs() {
closeWebSocket()
store.dispatch('disconnect')
}
</script><template> <div class="connect"> ? ? ? ? ? <el-button class="elbtn" @click="connectMsg">連接設(shè)備</el-button> ? ? ? ? <el-button class="elbtn" @click="closeWs">關(guān)閉設(shè)備</el-button> ? ? ? ? </div> </template>
④發(fā)送消息給后端
<script setup lang="ts">
import {ref} from 'vue'
import { sendWebSocket } from '../../utils/websocket'
const courseTopic = ref('')
const courseGrowth = ref('')
const todayHaul = ref('')
const selectedTeacher = ref('')
//提交
const harvestSubmit = () => {
? // 要發(fā)送的數(shù)據(jù)? 和后端定義格式
? const harvestData = {
? ? "HandlerType": "COURSEREFLECT",
? ? "topicReflect": courseTopic.value,
? ? "growReflect": courseGrowth.value,
? ? "harvest": todayHaul.value,
? ? "teacher": "李老師"
}
? ? console.log("提交反思與收獲數(shù)據(jù)",harvestData);?
? // 發(fā)送消息給后端
? ? sendWebSocket(harvestData)
? }
</script>
<template>
? ? ? ? <div class="think">
? ? ? ? ? <p>課程反思</p>
? ? ? ? <el-input v-model="courseTopic" :rows="3" type="textarea" placeholder="主題課程" />
? ? ? ? <el-input v-model="courseGrowth" :rows="3" type="textarea" placeholder="適性成長課程" />
? ? ? ? <p>今日收獲</p>
? ? ? ? <el-input v-model="todayHaul" :rows="3" type="textarea" ?/>
? ? ? ? </div>
? ? ? ? <div class="btn">
? ? ? ? ? ? <button @click="harvestSubmit"> 提交</button>
? ? ? ? ? </div>
? ? </template>總結(jié)
到此這篇關(guān)于如何使用vue3簡單實(shí)現(xiàn)WebSocket通信的文章就介紹到這了,更多相關(guān)vue3實(shí)現(xiàn)WebSocket通信內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue中for循環(huán)更改數(shù)據(jù)的實(shí)例代碼(數(shù)據(jù)變化但頁面數(shù)據(jù)未變)
這篇文章主要介紹了vue中for循環(huán)更改數(shù)據(jù)的實(shí)例代碼(數(shù)據(jù)變化但頁面數(shù)據(jù)未變)的相關(guān)資料,需要的朋友可以參考下2017-09-09
VUE動態(tài)綁定class類的三種常用方式及適用場景詳解
文章介紹了在實(shí)際開發(fā)中動態(tài)綁定class的三種常見情況及其解決方案,包括根據(jù)不同的返回值渲染不同的class樣式、給模塊添加基礎(chǔ)樣式以及根據(jù)設(shè)計(jì)確定是否使用多個(gè)樣式2025-01-01
Vue使用Vue-cropper實(shí)現(xiàn)圖片裁剪
這篇文章主要為大家詳細(xì)介紹了Vue使用Vue-cropper實(shí)現(xiàn)圖片裁剪,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
Vue報(bào)錯:TypeError:Cannot create property '
這篇文章主要介紹了Vue報(bào)錯:TypeError:Cannot create property 'xxx' on string 'xxxx'問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08
Vue項(xiàng)目打包問題詳解(生產(chǎn)環(huán)境樣式失效)
在Vue開發(fā)過程中,項(xiàng)目的打包是一個(gè)非常重要的步驟,下面這篇文章主要給大家介紹了關(guān)于Vue項(xiàng)目打包問題(生產(chǎn)環(huán)境樣式失效)的相關(guān)資料,文中介紹的非常詳細(xì),需要的朋友可以參考下2023-12-12
淺談Vue render函數(shù)在ElementUi中的應(yīng)用
今天小編就為大家分享一篇淺談Vue render函數(shù)在ElementUi中的應(yīng)用,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-09-09

