综合 |vuex与websoket应用

需求是获取导出记录。特点,无论哪个路由都能访问记录;进行导出操作时,等待后台处理后会通过websocket传来下载数据并重新渲染记录

效果

效果

vuex

import { getExportLogs } from "@/api/login";

const store = new Vuex.Store({
  //全局状态
  state: {
    logs:[],//导出记录
  },
    
  getters: {
    logs:state=>state.logs,
  },
  
  //改变状态
  mutations:{
    SET_LOGS(state, val) {
        state.logs = val;
    },
  },
  
  //异步事件
  actions:{
   _getLogs({ commit }) {
    return new Promise((resolve, reject) => {
      getExportLogs()//调用函数-获取导出记录
        .then(res => {
          if (res.msg == 'ok') { 
            commit("SET_LOGS", res.data);//调用成功时重置状态
            resolve(res.data);//传出导出记录数据
          } 
        .catch(error => {
          reject(error);
        });
    });
  }
    
})



挂载时调用:导出记录我做成了一个组件,镶嵌在页面的头部组件里。这里是指导出记录的组件挂载时

import { mapGetters } from 'vuex'

export default{
	async mounted(){
	    this.$store.dispatch("user/_getLogs")
	},
	
	//以便数据更新时视图能实时渲染
	computed: {
	    ...mapGetters([
	        'logs',
	    ])
	},
}

websocket

流程是建立连接——绑定账号(省略)——进行了导出操作后,待后台处理完毕后会发送数据过来,这时候前端就负责弹出这个下载框

心跳检测参考:https://www.jianshu.com/p/1141dcf6de3e

import store from "@/store/index";
import { Message } from "element-ui";

export default function initWebsocket() {
    //心跳检测,每28秒发送一次信息,防止断开连接
    var heartCheck = {
        timeout: 28000,
        timeoutObj: null,
        serverTimeoutObj: null,
        reset: function(){
            clearTimeout(this.timeoutObj);
            clearTimeout(this.serverTimeoutObj);
            return this;
        },
        start: function(){
            var self = this;
            this.timeoutObj = setTimeout(function(){
                //这里发送一个心跳,后端收到后,返回一个心跳消息,
                //onmessage拿到返回的心跳就说明连接正常
                ws.send("HeartBeat");
                self.serverTimeoutObj = setTimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了
                    ws.close();     //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
                }, self.timeout)
            }, this.timeout)
        }
    }

    var lockReconnect = false;  //避免ws重复连接
    var ws = null;          // 判断当前浏览器是否支持WebSocket
    var wsUrl = "ws://url"
    createWebSocket(wsUrl);   //连接ws

    //创建websocket
    function createWebSocket(url) {
        try{
            if('WebSocket' in window){
                ws = new WebSocket(url);
            }else if('MozWebSocket' in window){  
                ws = new MozWebSocket(url);
            }else{
                layui.use(['layer'],function(){
                  var layer = layui.layer;
                  layer.alert("您的浏览器不支持websocket协议,建议使用新版谷歌、火狐等浏览器,请勿使用IE10以下浏览器,360浏览器请使用极速模式,不要使用兼容模式!"); 
                });
            }
            initEventHandle();
        }catch(e){
            reconnect(url);
            console.log(e);
        }     
    }
	
    //回调处理
    function initEventHandle() {
        // 成功连接
        ws.onopen = function () {
            heartCheck.reset().start();      //心跳检测重置
            console.log("连接成功"+new Date().toUTCString());
        };
        
        // 接收信息
        ws.onmessage = async function (event) {    //如果获取到消息,心跳检测重置
            heartCheck.reset().start();      //拿到任何消息都说明当前连接是正常的
            
            // 获取数据
            let data=JSON.parse(event.data)
            // 弹出下载框
            if(data.type=='down_excel'){
                openDownloadDialog(data.url,data.file_name)
            }
            
        }
            
        ws.onclose = function () {
            reconnect(wsUrl);
            console.log("连接关闭!"+new Date().toUTCString());
        };
            
        ws.onerror = function () {
            reconnect(wsUrl);
            console.log("连接错误!");
        };
    }

    function reconnect(url) {
        if(lockReconnect) return;
        lockReconnect = true;
        setTimeout(function () {     //没连接上会一直重连,设置延迟避免请求过多
            createWebSocket(url);
            lockReconnect = false;
        }, 2000);
    }

    //弹框-接受到websocket传过来的下载数据时才会调用该函数
    function openDownloadDialog(url, saveName){
        //调用函数就说明后台已经异步处理完导出了,这时候派发事件重新渲染导出记录
        store.dispatch("_getLogs")
        window.open(url);
        Message.success('导出成功!')
    }
}

建立连接

App.vue

import initWebsocket from '@/utils/createWebSocket'
export default {
  name: "App",
  mounted(){
    initWebsocket()
  }
};
posted @ 2021-04-02 11:03  sanhuamao  阅读(899)  评论(0编辑  收藏  举报