当前位置:首页 » 《资源分享》 » 正文

Vue2 使用WebSocket实现前端与后端的实时通讯

27 人参与  2024年03月29日 09:40  分类 : 《资源分享》  评论

点击全文阅读


功能描述:WebSocket是一种在单个TCP连接上进行全双工通信的协议,它能够在客户端和服务器之间建立持久的连接,使得实时通讯成为可能。在前端开发中,WebSocket通常用于实现实时消息推送、实时数据更新等功能,为用户提供更流畅、即时的体验

本文将介绍如何在前端项目中利用WebSocket实现与后端的实时通讯,并结合具体的代码示例进行讲解。

实现单例模式的SocketService类

在本文中,我们将使用一个名为SocketService的类来封装WebSocket的相关操作,并通过单例模式确保在整个应用程序中只有一个SocketService实例存在。这样可以避免多次实例化和重复连接服务器的问题,同时方便在应用程序的不同模块中共享同一个SocketService实例,实现统一的数据传输和处理逻辑。

创建utils文件夹--->websocket.js文件

import { LoginWebSocketApi } from "@/request/api";export default class SocketService {    // 用于实现单例模式的写法    // 可以确保在整个应用程序中只有一个SocketService实例存在,避免了多次实例化和重复连接服务器的问题。通过单例模式,可以方便地在应用程序的不同模块中共享同一个SocketService实例,实现统一的数据传输和处理逻辑。    static instance = null;    static get Instance() {        if (!this.instance) {            this.instance = new SocketService()        }        return this.instance    }    ws = null    // 标识是否连接成功    connected = false    // 重试的次数    sendRetryCount = 0    // 重连的次数    connectRetryCount = 0    // 存储回调函数    // callBackMapping = {}    heartbeatInterval = null;    // 连接服务器的方法    connect(vue) {        // 连接服务器        if (!window.WebSocket) {            return console.log("浏览器不支持webSocket")        }        if (!localStorage.getItem("token")) {            console.log('没有token,不连接WebSocket');            return;        }        this.ws = new WebSocket("wss://你的地址");        // 连接成功的事件        this.ws.onopen = () => {            console.log("连接成功");            this.connected = true;            this.connectRetryCount = 0;            clearTimeout(this.heartbeatInterval);            this.start();        }        // 连接失败的事件        this.ws.onclose = () => {            console.log("连接失败")            this.connected = false;            if (this.connectRetryCount <= 100) {                this.connectRetryCount++            }            setTimeout(() => {                this.connect(vue)            }, this.connectRetryCount * 500)        }        // 收到数据的事件        this.ws.onmessage = (res) => {            // console.log("获取信息", res.data)            try {                console.log('接收消息', res.data);                let data_arr = JSON.parse(res.data);                let type = data_arr.type;                // 处理不同类型的消息                switch (type) {                    case 'login':                        this.login_websocket(data_arr.client_id);                        break;                    case 'charge_normal_end':                        vue.$bus.$emit('charge_normal_end', data_arr);                        break;                    case 'shots_count_change':                        vue.$bus.$emit('shots_count_change', data_arr);                        break;                    default:                        break;                }            } catch (e) {                console.log('e', e);            }        }    }    login_websocket(client_id) {        LoginWebSocketApi({            client_id: client_id,            ws_group: '首页'        }).then((webRes) => {            let ddd = {                type: 'login_success',                login_id: webRes.data.login_id            };            this.send(JSON.stringify(ddd));            console.log('发送登录消息', ddd);            this.manual_colse = false;        }).catch((err) => {            console.log('33err', err)        });    }    // 发送    send(data) {        // this.ws.send(data)        if (this.connected) {            this.sendRetryCount = 0;            this.ws.send(data)        } else {            this.sendRetryCount++            setTimeout(() => { }, this.sendRetryCount * 500)        }    }    // 关闭socket连接    close() {        if (this.ws) {            this.ws.close();            this.connected = false; // 更新连接状态            clearInterval(this.heartbeatInterval); // 清除心跳检测定时器        }    }    // 开启心跳检测    start() {        this.heartbeatInterval = setInterval(() => {            this.data = {                type: "ping"            };            this.send(JSON.stringify(this.data));        }, 5000);    }}

注意点:在webSocket.js这样的非Vue组件文件中,this并不指向Vue实例,因此无法直接通过this.$bus来访问事件总线,所以我这用的是vue.$bus.$emit.

在main.js文件中:我的事件总线是挂载在Vue原型上的,那么我在组件中就可以使用this.$bus来访问它

Vue.use(ElementUI);new Vue({  router,  store,  render: h => h(App),  beforeCreate() {    Vue.prototype.$bus = this  }}).$mount('#app')

在App.vue文件里的mounted生命周期钩子中执行,在登录成功后调用了SocketService.Instance.connect(this)来连接WebSocket。

<script>import SocketService from "./utils/websocket";import { AutoLoginApi } from "@/request/api";export default {  mounted() {    const token = localStorage.getItem("token");    if (token) {      AutoLoginApi()        .then(res => {          if (token) {            SocketService.Instance.connect(this);          }        })        .catch(error => {          console.log("自动登录error", error);        });    }  }};</script>

在需要监听数据的页面进行this.$bus.$on监听, this.$bus.$off 移除自定义事件监听器。

<script>export default {  data() {    return {    };  },  beforeDestroy() {    console.log("销毁");    this.stopListening();  },  created() {    this.startListening();  },  methods: {    startListening() {      this.$bus.$on("charge_normal_end", this.on_res_msg_charge_normal_end);      this.$bus.$on("shots_count_change", this.on_res_msg_shots_count_change);    },    stopListening() {      this.$bus.$off("charge_normal_end", this.on_res_msg_charge_normal_end);      this.$bus.$off("shots_count_change", this.on_res_msg_shots_count_change);    },    on_res_msg_charge_normal_end(data) {      //在这里处理逻辑      console.log("输出信息查看", data);    },    on_res_msg_shots_count_change(data) {      console.log("输出信息查看", data);    }  }};</script>

最后,在退出登录的时候,关闭webSocket

<script>import SocketService from "@/utils/websocket";export default {  data() {    return {          };  },  methods: {    // 退出登录    handleCommand(command) {     // 清除token        localStorage.removeItem("token");     // 关闭WebSocket连接        if (SocketService.Instance.connected) {          console.log("关闭WebSocket连接");          SocketService.Instance.ws.close();        }    }  }};</script>


点击全文阅读


本文链接:http://zhangshiyu.com/post/87465.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1