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