vue3+ ts 结合Vuex 去使用封装webscoket (建立两个地址连接、可手动销毁)

1 需求:

这个项目有两个地址,所以有两个不同的webscoket。(下面封装的可使用一个或者多个。)
并且要求,在不同页面可以共享数据。
(这个时候结合了vuex,这里的vuex使用的是vuex-module-decorators 详解

2.先看我的文件目录:

在这里插入图片描述

3.代码 - webscoket封装:

/utils/useWebSocket.ts 文件

/**
 * 该类负责创建 socket 连接
 */
export class UseWebSocket {
    
    
  // 该类socket地址
  private uri: string | undefined
  // 该类实例
  private static useWebSocket: UseWebSocket | undefined

  // websocket 实例
  private socket: WebSocket | undefined
  // 为true时,是心跳重连的websocket断开连接
  private lockReconnect = true

  // 心跳定时器
  private interval: any
  // 心跳间隔时间
  private longStartInterval = 30000

  // 消息超时延时
  private timeout: any
  // 消息超时延时时间
  private longStartTimeout = 5000

  // 用于传递消息
  private socketMsgMap: Map<string, Function> = new Map<string, Function>()

  public constructor (uri: string) {
    
    
    this.uri = uri
  }

  /**
   * 向该连接发送消息
   */
  public send (
    body: any
  ) {
    
    
    this.getSocketReadyState() === 1 && this.socket!.send(JSON.stringify(body))
  }

  /**
   * 监听该连接返回消息
   */
  public on (key: string, fun: (event: any) => void) {
    
    
    if (this.socketMsgMap.has(key)) return
    this.socketMsgMap.set(key, fun)
  }

  /**
   * 移除监听该连接返回消息
   */
  public removeOn (key: string) {
    
    
    this.socketMsgMap.delete(key)
  }

  /**
   * 主动关闭连接
   */
  public dispose () {
    
    
    // 心跳重连机制设置为 false
    this.lockReconnect = false
    this.socket && this.socket.close() // 离开路由之后断开websocket连接
    this.timeout && clearInterval(this.timeout)
    this.interval && clearTimeout(this.interval)
  }

  /**
   * 连接socket
   */
  public connectionSocket () {
    
    
    if (!this.socket && this.uri) {
    
    
      this.socket = new WebSocket(this.uri)
      // 建立监听事件
      this.creatListener()
    }
  }

  /**
   * 获取webSocket连接状态
   *     CONNECTING:值为0,表示正在连接。
   *     OPEN:值为1,表示连接成功,可以通信了。
   *     CLOSING:值为2,表示连接正在关闭。
   *     CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
   */
  public getSocketReadyState () {
    
    
    if (this.socket) {
    
    
      return this.socket.readyState
    }
    return 3
  }

  /**
   * 获取消息传递方法
   */
  public getSocketMsgFun (key: string) {
    
    
    const fun = key ? this.socketMsgMap.get(key) : this.socketMsgMap
    return fun
  }

  /**
   * 创建监听事件
   */
  private creatListener () {
    
    
    if (!this.socket) return
    this.socket.addEventListener('open', () => {
    
    
      console.log('socket连接成功!', this.socket)
      // 成功建立连接后,创建心跳检测
      this.longstart()
    })
    this.socket.addEventListener('message', (event: any) => {
    
    
      // 重置心跳
      this.longstart()
      let data = event.data
      try {
    
    
        data = JSON.parse(event.data)
      } catch (e) {
    
    
        // 返回的数据不是JSON类型
        console.log('收到data:', data)
        return
      }
      // 处理心跳消息 判断当前消息是否为心跳消息,是的话无需处理
      // if (data.header.messageType && data.header.messageType === IMessageType.heartbeat) return

      // 转发正常消息
      // const fun1 = this.socketMsgMap.get('socket:messagePage1')
      // fun1 && typeof fun1 === 'function' && fun1(data)
      // const fun2 = this.socketMsgMap.get('socket:messagePage2')
      // fun2 && typeof fun2 === 'function' && fun2(data)
      for (const [key, value] of this.socketMsgMap) {
    
    
        value && typeof value === 'function' && value(data)
      }
    })
    this.socket.addEventListener('error', (event: any) => {
    
    
      console.error(`Error from server: ${
      
      event}`)
    })
    this.socket.addEventListener('close', () => {
    
    
      this.socket = undefined
      if (this.lockReconnect) {
    
    
        this.uri && this.connectionSocket()
      }
    })
  }

  /**
   * 创建心跳检测
   */
  private longstart () {
    
    
    // 通过 关闭定时器 和 倒计时 进行重置心跳
    this.interval && clearInterval(this.interval)
    this.timeout && clearTimeout(this.timeout)
    // 每隔30s向后端发送一条数据需要跟后端协议发什么内容('ping' => 'pong')
    this.interval = setInterval(() => {
    
    
      // 重置监测心跳
      this.send({
    
    
        data: 'ping'
      })
      // 发送数据 5s后没有接收到返回的数据进行关闭websocket重连
      this.timeout = setTimeout(() => {
    
    
        // 心跳重连机制设置为 true
        this.lockReconnect = true
        // 此时不要清除 interval 定时器,持续发送心跳用于重连
        this.socket && this.socket.close()
      }, this.longStartTimeout)
    }, this.longStartInterval)
  }
}

/utils/mangerSocket.ts 文件

import {
    
     UseWebSocket } from './useWebSocket'

/**
 * 该类负责管理 socket 连接
 */
class MangerSocket {
    
    
  private static mangerSocket: MangerSocket | undefined
  public dataSocket: UseWebSocket | undefined
  public warningSocket: UseWebSocket | undefined

  private constructor () {
    
    
	//配置 dataSocket 地址
    this.dataSocket = new UseWebSocket('ws://10.111.182.120:8060')
    // 配置warningSocket 地址
    this.warningSocket = new UseWebSocket('ws://10.111.182.120:8070')
	// 这里是我打印用于查看webscoket状态的,所以注释掉了
    // setInterval(() => {
    
    
    //   console.log('this.warningSocket:',this.warningSocket)
    //   this.warningSocket && console.log('::', this.warningSocket.getSocketReadyState())
    // }, 3000)
  }

  /**
   * 获取该类实例
   */
  static instance (): MangerSocket {
    
    
    if (!this.mangerSocket) {
    
    
      this.mangerSocket = new MangerSocket()
    }
    return this.mangerSocket
  }

  /**
   * 主动关闭dataSocket连接
   */
  public disposeData () {
    
    
    this.dataSocket && this.dataSocket.dispose()
  }

  /**
   * 主动关闭warningSocket连接
   */
  public disposeWarning () {
    
    
    this.warningSocket && this.warningSocket.dispose()
  }
}
export default MangerSocket.instance()

4. 代码 - 结合Vuex 实现多个页面共享数据

/store/modules/mangerSocket.ts

import {
    
     VuexModule, Module, Mutation, getModule } from 'vuex-module-decorators'
import {
    
     Store } from 'vuex'
import mangerSocket from '@/utils/mangerSocket'
export const store = new Store({
    
    })

@Module({
    
     dynamic: true, store, name: 'keymangerSocket' })

class keymangerSocket extends VuexModule {
    
    
//这里是定义的socket 返回的数据格式
  public dataRes: {
    
    
    AlarmFlag: string
    AlarmMessage: any
    status: string
    nowTime: string
    rplStatus: string
  } = {
    
    
    AlarmFlag: '',
    AlarmMessage: '',
    status: '',
    nowTime: '',
    rplStatus: ''
  };

  @Mutation
  initWebsocket () {
    
    
  // 这里是获取两个socket中 warningSocket 的数据(这里是拿warningSocket举例子)
    mangerSocket.warningSocket && mangerSocket.warningSocket.on('socket:messagePage1', (data) => {
    
    
      console.log('webSocket警报:', data)
      this.dataRes = data
    })
    // //-------------这里是我模拟的数据,可以更改自己的数据格式
    // let n = 0
    // const a = setInterval(() => {
    
    
    //   const data = {
    
    
    //     AlarmFlag: '1',
    //     AlarmMessage: '{"用户报警代码": "3908","报警信息(中文)": "示教器未连接","报警原因(中文)": "示教器未连接。","解决办法(中文)": "检查示教器是否连接好。"}',
    //     status: '1',
    //     nowTime: '2022-11-08 16:09:22',
    //     rplStatus: '7'
    //   }
    //   const alarmMsg: {[key: string]: string} = JSON.parse(data.AlarmMessage)
    //   this.dataRes = {
    
    
    //     ...data,
    //     nowTime: '2022-11-08 16:09:2' + ++n,
    //     AlarmMessage: alarmMsg
    //   }
    // }, 5000)
    // // -------------------------------------结束
  }
}
export const KeymangerSocket = getModule(keymangerSocket)

页面中使用

import {
    
     KeymangerSocket } from '@/store/modules/mangerSocket'
export default defineComponent({
    
    
  setup () {
    
    
	const dataResLIst =  reactive({
    
    })
	// watch 监听获取socket数据
    watch(() => KeymangerSocket.dataRes, (newVal: any) => {
    
    
      dataResLIst = newVal
    }, {
    
     immediate: true, deep: true })
 	onMounted(() => {
    
    
 	  KeymangerSocket.initWebsocket()
      // 进入页面连接 warningSocket
      mangerSocket.warningSocket && mangerSocket.warningSocket.connectionSocket()
      console.log('连接warningSocket成功')
   })
    return {
    
    
      KeymangerSocket,
      dataResLIst 
    }
  }
})
// 如果需要销毁 关闭
mangerSocket.warningSocket && mangerSocket.disposeWarning()

猜你喜欢

转载自blog.csdn.net/weixin_55042716/article/details/128076098