websocket封装vue组件使用

1.store文件夹下新建一个index.js文件,稍后用到

//index.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
  state: {
    userInfo: null, // 保存用户信息,看具体情况自行编写
    socketAction: '', //socket接受消息数据
  },
  mutations: {
    //socket接受消息数据
    setSocketAction(state, data) {
      state.socketAction = data;
    },
  },
  getters: {},
  actions: {
  },
  modules: {},
});

2. 新建webSocket.vue文件(可直接cv使用,随便放个文件夹都行,后续引入注意路径)

//webWocket.vue
<template>
  <div class="zzh_webSocket"></div>
</template>

<script>
import Vue from 'vue';
import { mapState } from 'vuex';
export default {
  name: 'zzh_webSocket',
  props: [],
  components: {},
  computed: {
    ...mapState({
      userInfo: state => state.userInfo,
      work_no: state => state.work_no,
    }),
  },
  data() {
    return {
      websocketUrl: 'wx:xxxxx',
      heartbeat: null, //心跳包定时器
      //心跳包
      heartbeatData: {
        event_name: 'ping',
        work_no: '',
      },
      isConnect: false, //链接状态
      webSocket: null, //socket对象
      // globalCallback: {}, //事件函数
      reConnectNum: 0, //重连次数
    };
  },
  methods: {
    initWebSocket() {
      this.heartbeatData.work_no = this.work_no;
      //获取信息------------------------------------------
      let that = this;
      if ('WebSocket' in window) {
        this.webSocket = new WebSocket(this.websocketUrl); //创建socket对象
        //打开
        this.webSocket.onopen = this.webSocketOpen;
        //收信
        this.webSocket.onmessage = this.webSocketOnMessage;
        //关闭
        this.webSocket.onclose = this.webSocketOnClose;
        //连接发生错误的回调方法
        this.webSocket.onerror = this.webSocketOnError;
        //绑定到原型上方便调用,也可以绑定到vuex里面
        Vue.prototype.$socketChatApi = {
          sendSock: this.sendSock,
        };
        this.start();
      }
    },
    start() {
      this.isConnect = true;
      this.reConnectNum++;
      clearInterval(this.heartbeat);
      this.heartbeat = null;
      this.heartbeat = setInterval(() => {
        //40秒心跳包
        if (this.isConnect) {
          this.reConnectNum = 0;
          this.webSocketSend(this.heartbeatData);
        } else {
          clearInterval(this.heartbeat);
          this.heartbeat = null;
        }
      }, 40000);
    },
    webSocketOpen() {
      //首次握手  //这一段看后端需要绑定uid就写,不需要可以省略
      this.webSocketSend({
        event_name: 'bindUid',
        work_no: this.heartbeatData.work_no,
      });
      // console.log('socket🙈🙈🙈------首次握手');
    },
    //收到消息
    webSocketOnMessage(e) {
      const res = JSON.parse(e.data); //根据自己的需要对接后端收到的数据进行处理
      if (res.code == 1) {
        console.log('error!!!', JSON.parse(JSON.stringify(res)));
        return this.$message.error(res.msg || 'Response error');
      } else if (res.event_name == 'ping') {
        return;
      } else {
        console.log('socket🙈🙈🟢收:', JSON.parse(JSON.stringify(res)));
        return this.$store.commit('setSocketAction', res);
      }
    },
    //关闭时触发
    webSocketOnClose(e) {
      this.isConnect = false;
      clearInterval(this.heartbeat);
      console.log('socket🙈🙈🙈已经关闭 (code:' + e.code + ')- ' + this.reConnectNum, e);
      if (this.reConnectNum < 3) {
        this.initWebSocket();
      } else {
        //60s重连一次
        clearTimeout(this.zzh_timer);
        this.zzh_timer = null;
        this.zzh_timer = setTimeout(() => {
          if (!this.isConnect) {
            console.log('socket🙈🙈🙈*********尝试自动连接************');
            this.initWebSocket();
          }
        }, 60000);
      }
    },
    webSocketOnError(e) {
      clearInterval(this.heartbeat);
      this.heartbeat = null;
      this.isConnect = false; //断开后修改标识
      console.log('socket🙈🙈🙈连接出错:', e);
    },
    //发送数据
    webSocketSend(data) {
      console.log('socket🙈🙈➡️发:', JSON.parse(JSON.stringify(data)));
      this.webSocket.send(JSON.stringify(data)); //在这里根据自己的需要转换数据格式
    },
    //在其他需要socket地方调用的函数,用来发送数据及接受数据
    sendSock(agentData, callback) {
      //0 正在连接 1连接成功 2正在关闭 3已经关闭
      if ([0, 2].includes(this.webSocket.readyState)) {
        setTimeout(() => {
          this.sendSock(agentData, callback);
        }, 1000);
      } else if ([1].includes(this.webSocket.readyState)) {
        this.webSocketSend(agentData);
      }
    },
    //在其他需要socket地方主动关闭socket(如退出登录) 根据需求自行更改
    closeWebSocket(e) {
      return;
      this.sendSock({
        event_name: 'logout',
      });
      setTimeout(_ => {
        clearInterval(this.heartbeat);
        this.heartbeat = null;
        this.webSocket.close();
        this.isConnect = false;
        this.reConnectNum = 0;
      }, 500);
    },
    //防抖
    trottle(func, wait) {
      let context, args;
      // 之前的时间戳
      let old = 0; // 默认为0
      return function() {
        context = this;
        args = arguments;
        // 获取当前的时间戳
        let now = new Date().valueOf();
        if (now - old > wait) {
          // 立即执行
          func.apply(context, args);
          old = now;
        }
      };
    },
  },
  created() {
    this.initWebSocket();
  },
  mounted() {
    let that = this;
    //这三个函数的主要作用是起到无感刷新,例如电脑长时间不在睡眠状态socket可能会断开,所以监听鼠标移动重新链接
    window.addEventListener('online', () => {
      setTimeout(_ => {
        if (!that.isConnect) {
          console.log('socket🙈🙈🙈网络恢复----');
          that.initWebSocket();
        }
      }, 3000);
    });
    window.addEventListener('offline', () => {
      console.log('socket🙈🙈🙈网络离线===');
      that.initWebSocket();
    });
    window.addEventListener(
      'mousemove',
      that.trottle(function() {
        setTimeout(_ => {
          if (!that.isConnect) {
            console.log('socket🙈🙈🙈=====执行重连');
            that.initWebSocket();
          }
        }, 1000);
      }, 10000)
    );
  },
};
</script>

<style lang="less">
.zzh_webSocket {
}
</style>

3.使用

在需要用到socket的地方直接引入加载,可以放到index.vue或者app.vue都行,看具体使用场景

<template>
  <div class="zzh_index">
    <webSocket style="position: absolute;z-index: -1;"></webSocket>
  </div>
</template>

<script>
import webSocket from '@/views/webSocket.vue';//注意修改路径
import { mapState } from 'vuex';
export default {
  name: 'zzh_index',
  props: [],
  components: {
    webSocket,
  },
  data() {
    return {};
  },
  computed: {
    ...mapState({
      userInfo: state => state.userInfo,
      socketAction: state => state.socketAction, //重点!!!!!!!!!
    }),
  },
  watch: {
    //!!!!!这里可以监听到每次socket触发的事件,拿到数据
    async socketAction(res) {
      //返回的数据结构可与后端确定好就行,
      //例如 {event_name:'bindUid',data:'aaa'}
      switch (res.event_name) {
        //想监听那个事件,就写相应case就行
        case 'bindUid':
          // this.$store.commit('SET_USERINFO', {
          //   id: res.data.work_no,
          //   displayName: res.data.user_name,
          //   avatar: res.data.avatar,
          // });
          break;
      }
    },
  },
  methods: {},
  async created() {},
  async mounted() {},
};
</script>

<style></style>

写的匆忙,有遗漏的地方滴滴我

  • 18
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值