0
点赞
收藏
分享

微信扫一扫

WebSocket 就是个不停刷接口?你真的玩转 Vue 实时通信了吗?

七公子706 17小时前 阅读 1

哈喽,各位小伙伴,欢迎来到我是wangfang呀的博客!我是我是wangfang呀,虽然还在编程的“菜鸟”阶段,但我已经迫不及待地想和大家分享我一路上踩过的坑和学到的小技巧。如果你也曾为bug头疼,那么你来对地方了!今天的内容希望能够给大家带来一些灵感和帮助。

前言

  现代前端再也离不开 实时交互——股票行情、在线聊天、实时监控……只靠轮询不仅延迟高,还浪费资源。WebSocket 才是解决方案:双向持久连接、一推双击、秒级响应。今天我们就用 Vue 来手把手演示 WebSocket 客户端集成 → 实时数据推送与 UI 更新 → 心跳保活与断线重连 → 消息队列与展示,保证让你秒懂实时通信套路!

一、WebSocket 客户端在 Vue 中如何集成

1.1 最简单的原生用法

// src/utils/ws.js
export function createWebSocket(url, protocols = []) {
  const ws = new WebSocket(url, protocols);

  ws.onopen = () => console.log('WebSocket 已连接');
  ws.onmessage = evt => console.log('收到消息:', evt.data);
  ws.onclose = () => console.log('WebSocket 已断开');
  ws.onerror = err => console.error('WebSocket 错误', err);

  return ws;
}

1.2 在 Vue 应用中封装为插件

// src/plugins/websocket.js
import { createApp } from 'vue';
import { createWebSocket } from '@/utils/ws';

export default {
  install(app, { url, protocols }) {
    const ws = createWebSocket(url, protocols);
    app.config.globalProperties.$ws = ws;
    app.provide('ws', ws);
  }
};

// main.js
import { createApp } from 'vue';
import App from './App.vue';
import WebSocketPlugin from './plugins/websocket';

createApp(App)
  .use(WebSocketPlugin, { url: 'wss://example.com/socket' })
  .mount('#app');

组件中即可通过 this.$wsinject('ws') 来访问同一个 WebSocket 实例。

二、实时数据推送与 UI 更新

2.1 在组件中监听并渲染

<template>
  <div>
    <h2>实时行情</h2>
    <ul>
      <li v-for="item in quotes" :key="item.symbol">
        {{ item.symbol }}: {{ item.price }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref, onMounted, inject } from 'vue';

const ws = inject('ws');
const quotes = ref([]);

onMounted(() => {
  ws.onmessage = event => {
    const data = JSON.parse(event.data);
    // 假设 data = { symbol: 'AAPL', price: 123.45 }
    // 更新或插入
    const idx = quotes.value.findIndex(q => q.symbol === data.symbol);
    if (idx >= 0) quotes.value[idx].price = data.price;
    else quotes.value.push(data);
  };
});
</script>

要点:Vue 的响应式 ref([]) 能自动触发视图更新,拿到服务端推送后直接改数组即可。

三、心跳机制与断线重连

长连接偶尔会因网络抖动断开,我们需要「定期心跳」+「重连策略」。

// src/utils/ws.js
export function createWebSocket(url, protocols = []) {
  let ws;
  let heartbeatTimer;
  let retryTimer;
  const HEARTBEAT_INTERVAL = 30000;      // 30s
  const RECONNECT_DELAY = 5000;         // 5s

  function connect() {
    ws = new WebSocket(url, protocols);

    ws.onopen = () => {
      console.log('WS 连接成功');
      startHeartbeat();
    };

    ws.onmessage = evt => {
      if (evt.data === 'pong') return;  // 心跳回复
      // 其他消息交给外层重写
    };

    ws.onclose = () => {
      console.log('WS 已关闭,准备重连');
      stopHeartbeat();
      scheduleReconnect();
    };

    ws.onerror = err => {
      console.error('WS 错误', err);
      ws.close();
    };
  }

  function startHeartbeat() {
    clearInterval(heartbeatTimer);
    heartbeatTimer = setInterval(() => {
      if (ws.readyState === WebSocket.OPEN) {
        ws.send('ping');
      }
    }, HEARTBEAT_INTERVAL);
  }

  function stopHeartbeat() {
    clearInterval(heartbeatTimer);
  }

  function scheduleReconnect() {
    clearTimeout(retryTimer);
    retryTimer = setTimeout(connect, RECONNECT_DELAY);
  }

  connect();
  return {
    send: message => ws.readyState === WebSocket.OPEN && ws.send(message),
    onmessage: null, // will be reassigned by consumer
    close: () => {
      clearInterval(heartbeatTimer);
      clearTimeout(retryTimer);
      ws.close();
    }
  };
}

机制说明:每 30 秒发一次“ping”,服务端返回“pong”;连接断开后 5 秒自动重连。

四、实时消息展示与消息队列

大量消息到来时,直接往数组推入会造成 UI 卡顿,可使用「消息队列 + 节流渲染」。

<template>
  <div class="chat">
    <div v-for="msg in visibleMessages" :key="msg.id" class="message">
      {{ msg.text }}
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue';
import { createWebSocket } from '@/utils/ws';

const MSG_BATCH_SIZE = 20;
const allMessages = [];
const visibleCount = ref(MSG_BATCH_SIZE);

const visibleMessages = computed(() => {
  return allMessages.slice(0, visibleCount.value);
});

onMounted(() => {
  const ws = createWebSocket('wss://example.com/chat');
  ws.onmessage = evt => {
    allMessages.unshift(JSON.parse(evt.data));
    // 如果列表已滚到底部,自动增加可见条数
    if (visibleCount.value < allMessages.length) {
      visibleCount.value += 1;
    }
  };
});
</script>
  • 思想:所有消息先存进 allMessages,UI 只渲染 visibleMessages,避免一次性渲染几千条。
  • 可扩展:下拉加载历史消息时,减少 visibleCount

五、实战小结

  1. 封装统一的 WebSocket 管理:心跳 + 重连 + 事件转发。
  2. Vue 响应式更新:利用 ref/reactive,推送消息直接修改数据即可。
  3. 性能优化:节流、批量渲染、消息队列。
  4. 可扩展思路:支持多路分频道、订阅/退订、消息优先级等。

有了以上套路,不管是在线聊天、行情推送还是 IoT 数据监控,你的 Vue 实时通信都不会卡壳。 下一步,可以接入 Socket.IOSTOMP/WebSocket 或在 Nuxt.js 中使用中间件进行服务端渲染支持。

好啦,今天的内容就先到这里!如果觉得我的分享对你有帮助,给我点个赞,顺便评论吐个槽,当然不要忘了三连哦!感谢大家的支持,记得常回来,我是wangfang呀等着你们的下一次访问!

举报

相关推荐

0 条评论