WebSocket生命周期和vue中使用

进入页面,生命周期挂载后,window监听ws连接online

正常情况,心跳包检测避免断开

非正常情况,ws.onclose断开,
判断1000状态吗,触发重连函数。
定时器,重连,判断5次,每次增加30s,最后重新继续循环重连。

手动自主断开,正常断开,则不触发重连函数,直接ws.close断开

离开页面,ws.close断开,移除window监听ws连接online

<template>
  <!-- 大屏容器 -->
  <div class="dashboard-container">
    <!-- 动态连接状态指示器,根据connectionStatus改变样式 -->
    <div class="connection-status" :class="connectionStatus">
      {{ statusText }}
    </div>

    <!-- 数据卡片容器,使用自适应网格布局 -->
    <div class="dashboard">
      <!-- 用户数卡片 -->
      <DataCard
        title="实时用户数"
        :value="dashboardData.userCount"
        icon="👥"
        color="#4CAF50"
      />
      <!-- 销售额卡片,使用自定义货币格式化 -->
      <DataCard
        title="今日销售额"
        :value="dashboardData.sales"
        icon="💰"
        color="#2196F3"
        prefix="¥"
        :formatter="formatCurrency"
      />
      <!-- 订单卡片 -->
      <DataCard
        title="订单数量"
        :value="dashboardData.orders"
        icon="📦"
        color="#9C27B0"
      />
    </div>
  </div>
</template>

<script setup>
/* 核心逻辑模块 */
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue'
import DataCard from './components/DataCard.vue'

// 响应式数据存储(大屏核心数据)
const dashboardData = reactive({
  userCount: 0,    // 实时用户数
  sales: 0,        // 销售额(单位:元)
  orders: 0        // 订单数量
})

/* WebSocket连接管理 */
const connectionStatus = ref('connecting') // 连接状态:connecting/connected/disconnected
const statusText = ref('连接中...')         // 状态显示文本
const reconnectAttempts = ref(0)          // 当前重连尝试次数
const maxReconnectAttempts = 5            // 最大重连次数
const baseReconnectDelay = 1000           // 基础重连延迟(毫秒)
let ws = null                             // WebSocket实例引用
let heartbeatTimer = null                 // 心跳定时器
let reconnectTimer = null                 // 重连定时器

/**
 * 货币格式化方法
 * @param {number} value - 原始数值
 * @returns {string} 格式化后的货币字符串
 */
const formatCurrency = (value) => {
  return Number(value).toLocaleString('zh-CN', {
    style: 'currency',
    currency: 'CNY',
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
  })
}

/* WebSocket连接管理模块 */
/**
 * 初始化WebSocket连接
 * 1. 创建WebSocket实例
 * 2. 绑定事件处理器
 */
const initWebSocket = () => {
  // 创建WebSocket连接(生产环境应使用wss协议)
  ws = new WebSocket('wss://api.example.com/realtime-data')

  // 连接成功回调
  ws.onopen = () => {
    console.log('WebSocket connected')
    connectionStatus.value = 'connected'  // 更新连接状态
    statusText.value = '已连接'
    reconnectAttempts.value = 0          // 重置重连计数器
    startHeartbeat()                     // 启动心跳检测
  }

  // 消息接收处理
  ws.onmessage = (event) => {
    try {
      const data = JSON.parse(event.data)
      // 合并数据更新(触发响应式更新)
      Object.assign(dashboardData, {
        userCount: data.userCount,
        sales: data.sales,
        orders: data.orders
      })
    } catch (error) {
      console.error('数据解析失败:', error)
    }
  }

  // 连接关闭处理
  ws.onclose = (event) => {
    console.log('连接关闭:', event.code, event.reason)
    stopHeartbeat()  // 停止心跳
    // 非正常关闭时触发重连
    if (!event.wasClean) {
      handleReconnect()
    }
  }

  // 错误处理
  ws.onerror = (error) => {
    console.error('WebSocket 错误:', error)
    connectionStatus.value = 'disconnected'
    statusText.value = '连接异常'
    ws.close()  // 确保关闭连接
  }
}

/* 心跳机制模块 */
/**
 * 启动心跳检测
 * 每30秒发送一次ping消息保持连接
 */
const startHeartbeat = () => {
  heartbeatTimer = setInterval(() => {
    // 仅当连接处于打开状态时发送心跳
    if (ws?.readyState === WebSocket.OPEN) {
      ws.send(JSON.stringify({ type: 'ping' }))
    }
  }, 30000)
}

/**
 * 停止心跳检测
 */
const stopHeartbeat = () => {
  if (heartbeatTimer) {
    clearInterval(heartbeatTimer)
    heartbeatTimer = null
  }
}

/* 自动重连模块 */
/**
 * 自动重连机制(指数退避算法)
 * 1. 计算延迟时间:delay = base * 2^attempts
 * 2. 最大延迟不超过30秒
 * 3. 达到最大重试次数后停止
 */
const handleReconnect = () => {
  if (reconnectAttempts.value >= maxReconnectAttempts) {
    statusText.value = '连接失败,请刷新页面'
    return
  }

  connectionStatus.value = 'connecting'
  statusText.value = `正在重连 (${reconnectAttempts.value + 1}/${maxReconnectAttempts})`

  // 计算指数退避延迟
  const delay = Math.min(
    baseReconnectDelay * Math.pow(2, reconnectAttempts.value),
    30000 // 最大延迟30秒
  )

  // 设置重连定时器
  reconnectTimer = setTimeout(() => {
    reconnectAttempts.value++
    initWebSocket() // 重新初始化连接
  }, delay)
}

/* 资源清理模块 */
/**
 * 清理所有活动资源
 * 1. 关闭WebSocket连接
 * 2. 清除所有定时器
 */
const cleanup = () => {
  if (ws) {
    ws.close()
    ws = null
  }
  stopHeartbeat()
  if (reconnectTimer) {
    clearTimeout(reconnectTimer)
  }
}

/* 生命周期管理 */
onMounted(() => {
  // 初始化WebSocket连接
  initWebSocket()
  
  // 监听网络恢复事件
  window.addEventListener('online', () => {
    // 当连接不存在或已关闭时重新连接
    if (!ws || ws.readyState === WebSocket.CLOSED) {
      initWebSocket()
    }
  })
})

// 组件卸载前清理资源
onBeforeUnmount(() => {
  cleanup()
})
</script>

<style scoped>
/* 容器样式 */
.dashboard-container {
  padding: 20px;
  background: #000;
  min-height: 100vh;
  color: white;
}

/* 自适应网格布局 */
.dashboard {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 20px;
  max-width: 1920px;
  margin: 0 auto;
}

/* 连接状态指示器样式 */
.connection-status {
  position: fixed;
  top: 20px;
  right: 20px;
  padding: 8px 20px;
  border-radius: 20px;
  background: #ff4444;
  transition: all 0.3s;
}

/* 连接成功状态 */
.connection-status.connected {
  background: #00C851;
}

/* 连接中状态(带呼吸动画) */
.connection-status.connecting {
  background: #ffbb33;
  animation: pulse 1.5s infinite;
}

@keyframes pulse {
  0% { opacity: 1; }
  50% { opacity: 0.5; }
  100% { opacity: 1; }
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值