1. 創建socket.js類
import store from '@/store/index.js';
import API from '@/api/http.js';
// webScoket
let websock = {}; //建立的連接
let lockReconnect = false; //是否真正建立連接
let timeout = 60 * 1000; // 1分鐘一次心跳
let timeoutObj = null; //心跳心跳倒計時
let serverTimeoutObj = null; //心跳倒計時
let timeoutnum = null; //斷開 重連倒計時
// 一進入就加載
initWebSocket();
// 初始化weosocket
function initWebSocket() {
let user = localStorage.getItem('user');
if (user !== '' && user !== undefined) { // 在用戶未登錄的情況下不進行連接
// 建立連接
websock = new WebSocket ('你的webSocket地址');
// 連接成功
websock.onopen = websocketonopen;
// 連接錯誤
websock.onerror = websocketonerror;
// 連接關閉
websock.onclose = websocketclose;
// 接收信息
websock.onmessage = websocketonmessage;
} else {
//清除時間
clearTimeout(timeoutObj);
clearTimeout(serverTimeoutObj);
}
}
// 重新連接
function reconnect() {
if (lockReconnect) {
return;
}
lockReconnect = true;
// 沒連接上會一直重連,設置延遲避免請求過多
timeoutnum && clearTimeout(timeoutnum);
timeoutnum = setTimeout(function() {
// 新連接
initWebSocket();
lockReconnect = false;
}, 5000);
}
//重置心跳
function reset() {
//清除時間
clearTimeout(timeoutObj);
clearTimeout(serverTimeoutObj);
//重啓心跳
let user = localStorage.getItem('qrtMallUser');
if (!meetNull(user)) {
console.log('退出了登錄,不需要重連');
return;
}
start();
}
//開啓心跳
function start() {
timeoutObj && clearTimeout(timeoutObj);
serverTimeoutObj && clearTimeout(serverTimeoutObj);
timeoutObj = setTimeout(() => {
//這裏發送一個心跳,後端收到後,返回一個心跳消息,
if (websock.readyState == 1) {
//如果連接正常
websock.send("heartCheck");
} else {
//否則重連
reconnect();
}
serverTimeoutObj = setTimeout(() => {
//超時關閉
websock.close();
}, timeout);
}, timeout);
}
//連接成功事件
function websocketonopen() {
//開啓心跳
start();
}
//連接失敗事件
function websocketonerror(e) {
//錯誤
//重連
lockReconnect = false;
reconnect();
}
//連接關閉事件
function websocketclose(e) {
//關閉
console.log("connection closed ");
//提示關閉
//重連
reconnect();
}
function websocketsend(msg) {
//向服務器發送信息
//數據發送
if (websock.readyState == 1) {
websock.send(msg);
} else {
websock.close();
initWebSocket();
}
}
// 接收服務器返回的數據
function websocketonmessage(e) {
let resData = JSON.parse(e.data);
// 獲取當前在哪個路由,可以在路由文件存儲如:router.beforeEach((to, from, next) => {essionStorage.setItem('url', to.fullPath);});
let toUrl = sessionStorage.getItem('url');
if (resData.type == "init") {
// 請求接口綁定用戶到後端(API是我封裝的axios請求)
let para = {client_id: resData.client_id };
API.post("service/bind", para, 1).then(res => {
if (res.status == 1) {
store.commit('changeSocketLocal', websock);
}
});
} else if (resData.type == "msg_add") {
if ( toUrl == '/chat') {
// 正在聊天界面
store.commit('changeServiceInfosLocal', resData); // 把消息保存到Vuex中
} else { // 不在聊天界面中
eventStorage(); // 用於消息聲音提醒
// 設置未讀條數
let onReadMsgNum = localStorage.getItem("noReadNum"); // 把原有未讀的條數一起累加
++onReadMsgNum;
localStorage.setItem("noReadNum", onReadMsgNum);
store.commit('changeNoMsgReadNumLocal', onReadMsgNum); // 把未讀的條數保存到Vuex中,解決有新消息頁面未刷新不能及時更新的問題
}
}
// 收到服務器信息,心跳重置
reset();
}
function eventStorage () {
// 監聽storage的變化, 用於消息聲音提醒
var orignalSetItem = localStorage.setItem;
localStorage.setItem = function(key,newValue){
var setItemEvent = new Event("setItemEvent");
setItemEvent.newValue = newValue;
window.dispatchEvent(setItemEvent);
orignalSetItem.apply(this ,arguments);
}
}
export {
// 暴露出去,方便調用
initWebSocket
}
2.進入系統開啓websocket, 在main.js引入
import * as socket from '@/assets/js/socket.js'
Vue.prototype.$SOCKET = socket;
3.回顯webSocket的數據
<template>
<div class="cgh-view">{{dataList}}</div>
</template>
<script>
import { mapMutations, mapState } from 'vuex';
export default {
data() {
return {
webSocket: {readyState: 0},
dataList: []
};
},
created() {
localStorage.removeItem('noReadNum'); // 移除未讀消息
document.body.removeEventListener('setItemEvent', function (event) {
event.preventDefault(); // 移除對storage的監聽
},false);
this.changeNoMsgReadNumLocal(0); // 未讀數清零
},
computed: {
...mapState(['serviceInfosLocal', 'socketLocal'])
},
watch: {
serviceInfosLocal (newVal, oldval) { // 獲取客服發送的消息
this._getHttpMsgInfo(newVal.data);
},
socketLocal (newVal) { // 保存的webSoket對象, 用於獲取連接狀態
this.webSocket = newVal;
},
},
methods: {
...mapMutations(['changeNoMsgReadNumLocal']),
_getHttpMsgInfo (resData) { // 接收到服務器消息
let toUrl = sessionStorage.getItem('url');
if (toUrl.includes('chat')) {
// 在聊天界面,直接把消息push到數據裏,用於界面回顯
this.dataList.push(resData);
}
// 向服務器發送數據
if (this.webSocket !== undefined && this.webSocket.readyState == 1) {
this.webSocket.send(resData);
}
},
},
};
</script>
3.顯示未讀條數
<template>
<div class="cgh-tab-view">
<div class="cgh-msg-msg-on-read" >{{readNum}}</div>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
data() {
return {
readNum: "",
};
},
computed: {
...mapState(["noMsgReadNumLocal"])
},
created() {
let val = localStorage.getItem('noReadNum');
this.getNoReadMsg(val);
},
watch: {
noMsgReadNumLocal: { // 監聽Vuex noMsgReadNumLocal數據的變化
handler: function(val, oldval) {
this.getNoReadMsg(val);
}
}
},
methods: {
getNoReadMsg(val) {
// 獲取未讀條數
if (val !== '') {
this.readNum = "";
} else {
if (Number(val) > 99) {
this.readNum = "99+";
} else {
this.readNum = val;
}
}
}
},
};
</script>
4.新消息聲音提醒
在index.html寫入:
<body>
<audio style="display:none;" id='MsgaudioTs'>
<source src="msg.mp3" />
</audio>
</body>
<script>
// 客服新信息聲音提醒
window.addEventListener("setItemEvent", function (e) {
if (localStorage.getItem('noReadNum')) {
var elem = document.getElementById('MsgaudioTs');
//播放
if (elem.paused) {
elem.play();
}
}
});
</script>