代码封装
编写 WebSocketClient.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
| import { EventDispatcher } from './dispatcher'
export class WebSocketClient extends EventDispatcher { constructor(url) { console.log(url, 'urlurl') super() this.url = url }
socket = null reconnectAttempts = 0 maxReconnectAttempts = 5 reconnectInterval = 10000 heartbeatInterval = 1000 * 30 heartbeatTimer = undefined stopWs = false
onopen(callBack) { this.addEventListener('open', callBack) }
onmessage(callBack) { this.addEventListener('message', callBack) }
onclose(callBack) { this.addEventListener('close', callBack) }
onerror(callBack) { this.addEventListener('error', callBack) }
send(message) { if (this.socket && this.socket.readyState === WebSocket.OPEN) { this.socket.send(message) } else { console.error('[WebSocket] 未连接') } }
connect() { if (this.reconnectAttempts === 0) { this.log('WebSocket', `初始化连接中... ${this.url}`) } if (this.socket && this.socket.readyState === WebSocket.OPEN) { return } this.socket = new WebSocket(this.url)
this.socket.onopen = (event) => { this.stopWs = false this.reconnectAttempts = 0 this.startHeartbeat() this.log('WebSocket', `连接成功,等待服务端数据推送[onopen]... ${this.url}`) this.dispatchEvent('open', event) }
this.socket.onmessage = (event) => { this.dispatchEvent('message', event) this.startHeartbeat() }
this.socket.onclose = (event) => { if (this.reconnectAttempts === 0) { this.log('WebSocket', `连接断开[onclose]... ${this.url}`) } if (!this.stopWs) { this.handleReconnect() } this.dispatchEvent('close', event) }
this.socket.onerror = (event) => { if (this.reconnectAttempts === 0) { this.log('WebSocket', `连接异常[onerror]... ${this.url}`) } this.closeHeartbeat() this.dispatchEvent('error', event) } }
handleReconnect() { if (this.reconnectAttempts < this.maxReconnectAttempts) { this.reconnectAttempts++ this.log( 'WebSocket', `尝试重连... (${this.reconnectAttempts}/${this.maxReconnectAttempts}) ${this.url}` ) setTimeout(() => { this.connect() }, this.reconnectInterval) } else { this.closeHeartbeat() this.log('WebSocket', `最大重连失败,终止重连: ${this.url}`) } }
close() { if (this.socket) { this.stopWs = true this.socket.close() this.socket = null this.removeEventListener('open') this.removeEventListener('message') this.removeEventListener('close') this.removeEventListener('error') } this.closeHeartbeat() }
startHeartbeat() { if (this.stopWs) return if (this.heartbeatTimer) { this.closeHeartbeat() } this.heartbeatTimer = setInterval(() => { if (this.socket) { this.socket.send(JSON.stringify({ type: 'heartBeat', data: {} })) this.log('WebSocket', '送心跳数据...') } else { console.error('[WebSocket] 未连接') } }, this.heartbeatInterval) }
closeHeartbeat() { clearInterval(this.heartbeatTimer) this.heartbeatTimer = undefined } }
|
引用的 dispatcher.js
源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import { Log } from './log'
export class EventDispatcher extends Log { constructor() { super() this.listeners = {} }
addEventListener(type, listener) { if (!this.listeners[type]) { this.listeners[type] = [] } if (this.listeners[type].indexOf(listener) === -1) { this.listeners[type].push(listener) } }
removeEventListener(type) { this.listeners[type] = [] }
dispatchEvent(type, data) { const listenerArray = this.listeners[type] || [] if (listenerArray.length === 0) return listenerArray.forEach((listener) => { listener.call(this, data) }) } }
|
上面还用到了一个 log.js
,用于美化控制台打印的,这个文件在其他地方也通用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| export class Log { static console = true
log(title, text) { if (!Log.console) return const color = '#09c' console.log( `%c ${title} %c ${text} %c`, `background:${color};border:1px solid ${color}; padding: 1px; border-radius: 2px 0 0 2px; color: #fff;`, `border:1px solid ${color}; padding: 1px; border-radius: 0 2px 2px 0; color: ${color};`, 'background:transparent' ) }
closeConsole() { Log.console = false } }
|
至此一个 WebSocket 就封装好了
使用方法
首先使用node编写一个后端服务,用于 WebSocket 连接
需要安装一下 ws
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const WebSocket = require("ws");
const wss = new WebSocket.Server({port: 3200});
console.log("服务运行在http://localhost:3200/");
wss.on("connection", (ws) => { console.log("[服务器]:连接成功"); ws.send(`[websocket云端]您已经连接云端!等待数据推送~`);
ws.on("message", (res) => { ws.send(`[websocket云端]收到消息:${res.toString()}`); });
ws.on("close", () => { console.log("[服务器]:连接已关闭~"); }); });
|
然后我这里编写了一个简单的demo页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| <template> <div> <el-button type="primary" @click="connection">创建连接</el-button> <el-button type="danger" @click="close">关闭连接</el-button>
<el-input v-model="message" placeholder="placeholder"></el-input> <el-button type="primary" @click="send">发送消息</el-button>
<ul> <li v-for="(item, index) in messageList" :key="index">{{ item }}</li> </ul> </div> </template>
<script> import { WebSocketClient } from '@/utils/WebSocketClient'
export default { data() { return { message: '', messageList: [], ws: null, } }, methods: { connection() { if (this.ws) { this.close() } this.ws = new WebSocketClient('ws://localhost:3200') this.setupWebSocketListeners() this.ws.connect() }, close() { if (this.ws) { this.ws.close() this.ws = null } }, send() { if (this.ws) { this.ws.send(this.message) } }, setupWebSocketListeners() { this.ws.onmessage((msg) => { this.ws.log('WebSocketClient', msg.data) this.messageList.push(msg.data) }) this.ws.onopen(() => { this.ws.log('WebSocketClient', '连接已打开') }) this.ws.onclose(() => { this.ws.log('WebSocketClient', '连接已关闭') }) this.ws.onerror((error) => { this.ws.log('WebSocketClient', '连接错误') console.error(error) }) }, }, mounted() { this.connection() }, } </script>
|
初次连接

消息发送

关闭连接后,消息就无法发送了

再次连接
