当前位置:   article > 正文

在vue3中封装使用WebSocket_vue3 websocket封装

vue3 websocket封装

上篇文章记录了如何在日常开发过程中引入并使用websocket连接,但是在后续的开发过程中发现之前的写法有点问题,比如说多次引用连接会共用一个心跳,如果一个连接关掉了,后续其他的连接可能被一起关掉等等的bug。

所以在这篇文章里针对上篇文章提供的方法进行改进,同时提供兼容vue3写法。

一、创建 WebSocket

  1. class Socket {
  2. constructor(url, opts = {}) {
  3. this.url = url;
  4. this.ws = null;
  5. this.opts = {
  6. heartbeatInterval: 30000, // 默认30秒
  7. reconnectInterval: 5000, // 默认5秒
  8. maxReconnectAttempts: 5, // 默认尝试重连5次
  9. ...opts
  10. };
  11. this.reconnectAttempts = 0;
  12. this.listeners = {};
  13. this.init();
  14. }
  15. init() {
  16. this.ws = new WebSocket(this.url);
  17. this.ws.onopen = this.onOpen.bind(this);
  18. this.ws.onmessage = this.onMessage.bind(this);
  19. this.ws.onerror = this.onError.bind(this);
  20. this.ws.onclose = this.onClose.bind(this);
  21. }
  22. onOpen(event) {
  23. console.log('WebSocket opened:', event);
  24. this.reconnectAttempts = 0; // 重置重连次数
  25. this.startHeartbeat();
  26. this.emit('open', event);
  27. }
  28. onMessage(event) {
  29. console.log('WebSocket message received:', event.data);
  30. this.emit('message', event.data);
  31. }
  32. onError(event) {
  33. console.error('WebSocket error:', event);
  34. this.emit('error', event);
  35. }
  36. onClose(event) {
  37. console.log('WebSocket closed:', event);
  38. this.stopHeartbeat();
  39. this.emit('close', event);
  40. if (this.reconnectAttempts < this.opts.maxReconnectAttempts) {
  41. setTimeout(() => {
  42. this.reconnectAttempts++;
  43. this.init();
  44. }, this.opts.reconnectInterval);
  45. }
  46. }
  47. // 发送心跳
  48. startHeartbeat() {
  49. this.heartbeatInterval = setInterval(() => {
  50. if (this.ws.readyState === WebSocket.OPEN) {
  51. this.ws.send('ping'); // 可以修改为你的心跳消息格式
  52. }
  53. }, this.opts.heartbeatInterval);
  54. }
  55. // 停止心跳
  56. stopHeartbeat() {
  57. if (this.heartbeatInterval) {
  58. clearInterval(this.heartbeatInterval);
  59. this.heartbeatInterval = null;
  60. }
  61. }
  62. send(data) {
  63. if (this.ws.readyState === WebSocket.OPEN) {
  64. this.ws.send(data);
  65. } else {
  66. console.error('WebSocket is not open. Cannot send:', data);
  67. }
  68. }
  69. on(event, callback) {
  70. if (!this.listeners[event]) {
  71. this.listeners[event] = [];
  72. }
  73. this.listeners[event].push(callback);
  74. }
  75. off(event, callback) {
  76. if (!this.listeners[event]) return;
  77. const index = this.listeners[event].indexOf(callback);
  78. if (index !== -1) {
  79. this.listeners[event].splice(index, 1);
  80. }
  81. }
  82. emit(event, data) {
  83. if (this.listeners[event]) {
  84. this.listeners[event].forEach(callback => callback(data));
  85. }
  86. }
  87. }
  88. export default Socket;

我们首先定义一个 Socket 类,该类会负责与 WebSocket 服务器建立连接、发送和接收数据、以及管理心跳和重连逻辑。 

在你的Vue组件中使用这个类时,可以这样注册事件:

  1. import Socket from './socket.js';
  2. export default {
  3. data() {
  4. return {
  5. socket: null
  6. };
  7. },
  8. created() {
  9. this.socket = new Socket('ws://your-websocket-url');
  10. this.socket.on('open', event => {
  11. console.log("Connected to server", event);
  12. });
  13. this.socket.on('message', data => {
  14. console.log("Received data:", data);
  15. });
  16. this.socket.on('error', error => {
  17. console.error("WebSocket Error:", error);
  18. });
  19. this.socket.on('close', event => {
  20. console.log("Connection closed", event);
  21. });
  22. },
  23. beforeDestroy() {
  24. // 取消所有事件监听器
  25. this.socket.off('open');
  26. this.socket.off('message');
  27. this.socket.off('error');
  28. this.socket.off('close');
  29. },
  30. methods: {
  31. sendToServer(data) {
  32. this.socket.send(data);
  33. }
  34. }
  35. }

二、使用 Vue 3 的 Composition API

为了在 Vue 3 中更好地使用上述的 Socket 类,我们将其封装为一个 composable 函数,这样可以轻松地在任何 Vue 组件中使用 WebSocket。

  1. import { ref, onUnmounted } from 'vue';
  2. interface SocketOptions {
  3. heartbeatInterval?: number;
  4. reconnectInterval?: number;
  5. maxReconnectAttempts?: number;
  6. }
  7. class Socket {
  8. url: string;
  9. ws: WebSocket | null = null;
  10. opts: SocketOptions;
  11. reconnectAttempts: number = 0;
  12. listeners: { [key: string]: Function[] } = {};
  13. heartbeatInterval: number | null = null;
  14. constructor(url: string, opts: SocketOptions = {}) {
  15. this.url = url;
  16. this.opts = {
  17. heartbeatInterval: 30000,
  18. reconnectInterval: 5000,
  19. maxReconnectAttempts: 5,
  20. ...opts
  21. };
  22. this.init();
  23. }
  24. init() {
  25. this.ws = new WebSocket(this.url);
  26. this.ws.onopen = this.onOpen.bind(this);
  27. this.ws.onmessage = this.onMessage.bind(this);
  28. this.ws.onerror = this.onError.bind(this);
  29. this.ws.onclose = this.onClose.bind(this);
  30. }
  31. onOpen(event: Event) {
  32. console.log('WebSocket opened:', event);
  33. this.reconnectAttempts = 0;
  34. this.startHeartbeat();
  35. this.emit('open', event);
  36. }
  37. onMessage(event: MessageEvent) {
  38. console.log('WebSocket message received:', event.data);
  39. this.emit('message', event.data);
  40. }
  41. onError(event: Event) {
  42. console.error('WebSocket error:', event);
  43. this.emit('error', event);
  44. }
  45. onClose(event: CloseEvent) {
  46. console.log('WebSocket closed:', event);
  47. this.stopHeartbeat();
  48. this.emit('close', event);
  49. if (this.reconnectAttempts < this.opts.maxReconnectAttempts!) {
  50. setTimeout(() => {
  51. this.reconnectAttempts++;
  52. this.init();
  53. }, this.opts.reconnectInterval);
  54. }
  55. }
  56. startHeartbeat() {
  57. if (!this.opts.heartbeatInterval) return;
  58. this.heartbeatInterval = window.setInterval(() => {
  59. if (this.ws?.readyState === WebSocket.OPEN) {
  60. this.ws.send('ping');
  61. }
  62. }, this.opts.heartbeatInterval);
  63. }
  64. stopHeartbeat() {
  65. if (this.heartbeatInterval) {
  66. clearInterval(this.heartbeatInterval);
  67. this.heartbeatInterval = null;
  68. }
  69. }
  70. send(data: string) {
  71. if (this.ws?.readyState === WebSocket.OPEN) {
  72. this.ws.send(data);
  73. } else {
  74. console.error('WebSocket is not open. Cannot send:', data);
  75. }
  76. }
  77. on(event: string, callback: Function) {
  78. if (!this.listeners[event]) {
  79. this.listeners[event] = [];
  80. }
  81. this.listeners[event].push(callback);
  82. }
  83. off(event: string) {
  84. if (this.listeners[event]) {
  85. delete this.listeners[event];
  86. }
  87. }
  88. emit(event: string, data: any) {
  89. this.listeners[event]?.forEach(callback => callback(data));
  90. }
  91. }
  92. export function useSocket(url: string, opts?: SocketOptions) {
  93. const socket = new Socket(url, opts);
  94. onUnmounted(() => {
  95. socket.off('open');
  96. socket.off('message');
  97. socket.off('error');
  98. socket.off('close');
  99. });
  100. return {
  101. socket,
  102. send: socket.send.bind(socket),
  103. on: socket.on.bind(socket),
  104. off: socket.off.bind(socket)
  105. };
  106. }

在组件中使用:

  1. import { defineComponent } from 'vue';
  2. import { useSocket } from './useSocket';
  3. export default defineComponent({
  4. name: 'YourComponent',
  5. setup() {
  6. const { socket, send, on, off } = useSocket('ws://your-websocket-url');
  7. on('open', event => {
  8. console.log("Connected to server", event);
  9. });
  10. on('message', data => {
  11. console.log("Received data:", data);
  12. });
  13. on('error', error => {
  14. console.error("WebSocket Error:", error);
  15. });
  16. on('close', event => {
  17. console.log("Connection closed", event);
  18. });
  19. return {
  20. send
  21. };
  22. }
  23. });

三、总结

以上是具体实现方案,在后续开发过程中如果有更好的写法,也会更新本文。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/393000
推荐阅读
相关标签
  

闽ICP备14008679号