经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 大数据/云/AI » 人工智能基础 » 查看文章
ai问答:vue3+pinia+WebSocket 封装断线重连(实战)
来源:cnblogs  作者:让梦想纵横  时间:2023/5/8 10:21:12  对本文有异议

socket实例 挂载到全局

为方便梳理,请忽略typescript

  1. # main.ts
  2. import {createApp} from 'vue'
  3. import App from './App.vue'
  4. import {socket} from "@/xihu/socket"
  5. import router from "@/xihu/router"
  6. const app = createApp(App);
  7. app.use(router).mount('#root');
  8. // 全局挂载
  9. app.config.globalProperties.$socket = socket;

Socket封装(断线重连)

这个WebSocket类封装了WebSocket的连接、重连、发送数据等方法。
connect方法中,它会连接WebSocket,并绑定相关事件监听。
onclose事件中,它会调用reconnect方法进行重连。
reconnect方法会在一定时间内重连,并且重连的时间间隔会越来越长,最大重连次数达到设定值后就不再重连。
这样就实现了一个可以断线重连的WebSocket连接。
我们可以在vue应用中使用这个类来进行WebSocket通信,并处理可能出现的网络断开重连情况。

  1. # socket.ts
  2. // @ts-nocheck
  3. export default class Socket {
  4. constructor(url, protocols) {
  5. this.url = url
  6. this.protocols = protocols
  7. this.ws = null
  8. this.reconnectTimeout = 1000
  9. this.maxReconnectTimes = 5
  10. }
  11. connect() {
  12. this.ws = new WebSocket(this.url, this.protocols)
  13. this.ws.onopen = () => {
  14. console.log('WebSocket连接成功')
  15. this.reconnectTimes = 0
  16. }
  17. this.ws.onclose = () => {
  18. console.log('WebSocket断开连接')
  19. this.reconnect()
  20. }
  21. this.ws.onerror = err => {
  22. console.log('WebSocket连接出错', err)
  23. }
  24. }
  25. reconnect() {
  26. if (this.reconnectTimes < this.maxReconnectTimes) {
  27. setTimeout(() => {
  28. this.connect()
  29. this.reconnectTimes++
  30. }, this.reconnectTimeout)
  31. this.reconnectTimeout *= 2
  32. } else {
  33. console.log('WebSocket重连超过最大次数,放弃重连')
  34. }
  35. }
  36. // 消息发送
  37. msg(param) {
  38. if (param === 'heartbeat') {
  39. this.ws.send(param);
  40. } else {
  41. this.ws.send(JSON.stringify(param));
  42. }
  43. }
  44. // 延迟发送
  45. timeout(param) {
  46. setTimeout(() => {
  47. this.msg(param);
  48. }, 2000)
  49. }
  50. send(param) {
  51. if (this.ws.readyState === this.ws.OPEN) {
  52. this.msg(param);
  53. } else if (this.ws.readyState === this.ws.CONNECTING) {
  54. this.timeout(param);
  55. } else {
  56. this.timeout(param);
  57. }
  58. }
  59. }

实例化socket

通过type关键字,分发数据,并且通过pinia(vuex)存储实时数据
在消息回调函数,处理返回的数据,使用type关键字对应各种推送事件,比如:实时设备告警、地图显示用户坐标等等...

  1. // @ts-nocheck
  2. import {createPinia} from 'pinia';
  3. import {useAlarm} from '@/store/alarm';
  4. // 状态管理
  5. export const pinia = createPinia();
  6. export const store = useAlarm(pinia);
  7. export function wsInit(callback) {
  8. const url = 'ws://api.xx.cn';
  9. const init = new Socket(url);
  10. // 连接 WebSocket
  11. init.connect();
  12. // 监听 WebSocket
  13. init.ws.onmessage = function (ev) {
  14. if (ev && ev.data && ev.data.indexOf('subscribe') > -1) {
  15. console.log('subscribe->', ev.data);
  16. } else if (ev && ev.data) {
  17. var data = eval('(' + ev.data + ')');
  18. callback(data);
  19. }
  20. };
  21. return init;
  22. }
  23. // 消息回调
  24. export const socket = wsInit((data) => {
  25. switch (data.type) {
  26. case 1:
  27. store.setType1(data);
  28. break;
  29. case 2:
  30. store.setType2(data.message);
  31. break;
  32. }
  33. });
  34. // 心跳连接
  35. function heartbeat() {
  36. socket.send("heartbeat");
  37. }
  38. // 十分钟一次 (简陋心跳,也请忽略吧^_^)
  39. heartbeat();
  40. setInterval(heartbeat, 1000 * 60 * 10);

状态管理

  1. # alarm.ts
  2. import {defineStore} from 'pinia'
  3. export const useAlarm = defineStore('user', {
  4. state:()=>({
  5. type1:{},
  6. type2:{},
  7. }),
  8. getters:{
  9. getType1: (state) => state.type1,
  10. getType2: (state) => state.type2,
  11. },
  12. actions:{
  13. setType1(payload: any) {
  14. this.type1 = payload;
  15. },
  16. setType2(payload: any) {
  17. this.type2 = payload;
  18. },
  19. },
  20. })

在页面中,使用数据(pinia)

  1. # home.vue
  2. import { watch, computed, onMounted, getCurrentInstance} from 'vue'
  3. import {useAlarm} from "@/xihu/store/alarm";
  4. const store = useAlarm();
  5. // 还记得全局挂载的`$socket`吧,这样使用
  6. const ctx: any = getCurrentInstance();
  7. const {$socket} = ctx.appContext.config.globalProperties;
  8. onMounted(() => {
  9. // 列表数据 -- 通过给`websocket`发送`{"cmd":"1"}`实现数据交互
  10. $socket.send({cmd: 1});
  11. });
  12. const click = ()=>{
  13. // 其他数据 -- 点击列表的某一项,根据参数获取数据
  14. $socket.send({cmd: 2,extras:{id:123}});
  15. }
  16. // 第一种 监听方式:
  17. const type1 = computed(() => store.type1);
  18. watch(type1, (message: any) => {
  19. console.log('/computed/watch/', message);
  20. }, {deep: true});
  21. // 第二种 监听方式:
  22. store.$subscribe(({events}: any, state) => {
  23. if (events.key === 'type1') {
  24. console.log('/$subscribe/', state.type1);
  25. }
  26. });

大多数情况,数据是后台主动推送的,比如:告警数据,这也是使用websocket的主要原因

原文链接:https://www.cnblogs.com/vmto/p/17378285.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号