Vue 封裝WebSocket+檢測心跳+客服

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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章