Vue3 中 WebSocket 的全局封装
在 Vue3 中封装 WebSocket 可以实现全局的通信管理,便于在各个组件中使用。下面是一个完整的封装方案:
1. 创建 WebSocket 服务文件
首先创建一个 websocket.service.js
文件:
// src/services/websocket.service.js
class WebSocketService {
constructor() {
this.socket = null
this.messageListeners = []
this.reconnectAttempts = 0
this.maxReconnectAttempts = 5
this.reconnectInterval = 3000 // 3秒
}
connect(url) {
if (this.socket) {
this.disconnect()
}
this.socket = new WebSocket(url)
this.socket.onopen = () => {
console.log('WebSocket connected')
this.reconnectAttempts = 0
}
this.socket.onmessage = (event) => {
try {
const data = JSON.parse(event.data)
this.notifyListeners(data)
} catch (error) {
console.error('Error parsing WebSocket message:', error)
}
}
this.socket.onclose = (event) => {
console.log('WebSocket disconnected:', event.code, event.reason)
this.handleReconnect(url)
}
this.socket.onerror = (error) => {
console.error('WebSocket error:', error)
}
}
disconnect() {
if (this.socket) {
this.socket.close()
this.socket = null
}
}
handleReconnect(url) {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++
console.log(`Attempting to reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`)
setTimeout(() => this.connect(url), this.reconnectInterval)
} else {
console.log('Max reconnection attempts reached')
}
}
addMessageListener(callback) {
this.messageListeners.push(callback)
return () => {
this.messageListeners = this.messageListeners.filter(listener => listener !== callback)
}
}
notifyListeners(data) {
this.messageListeners.forEach(listener => listener(data))
}
sendMessage(message) {
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
const messageString = typeof message === 'string' ? message : JSON.stringify(message)
this.socket.send(messageString)
} else {
console.error('WebSocket is not connected')
}
}
}
// 创建单例实例
const webSocketService = new WebSocketService()
export default webSocketService
2. 在 Vue 应用中全局提供 WebSocket 服务
在 main.js
或 main.ts
中:
import { createApp } from 'vue'
import App from './App.vue'
import webSocketService from './services/websocket.service'
const app = createApp(App)
// 全局提供 WebSocket 服务
app.provide('websocket', webSocketService)
// 连接到 WebSocket 服务器
webSocketService.connect('ws://your-websocket-server.com')
app.mount('#app')
3. 在组件中使用 WebSocket
选项式 API 使用方式
<script>
export default {
inject: ['websocket'],
data() {
return {
messages: []
}
},
created() {
// 添加消息监听器
this.unsubscribe = this.websocket.addMessageListener(this.handleMessage)
},
beforeUnmount() {
// 移除消息监听器
if (this.unsubscribe) {
this.unsubscribe()
}
},
methods: {
handleMessage(data) {
this.messages.push(data)
console.log('Received message:', data)
},
sendMessage() {
const message = { text: 'Hello from Vue!', timestamp: new Date().toISOString() }
this.websocket.sendMessage(message)
}
}
}
</script>
组合式 API 使用方式
<script setup>
import { inject, onBeforeUnmount, ref } from 'vue'
const websocket = inject('websocket')
const messages = ref([])
const handleMessage = (data) => {
messages.value.push(data)
console.log('Received message:', data)
}
// 添加消息监听器
const unsubscribe = websocket.addMessageListener(handleMessage)
// 组件卸载前移除监听器
onBeforeUnmount(() => {
unsubscribe()
})
const sendMessage = () => {
const message = { text: 'Hello from Vue!', timestamp: new Date().toISOString() }
websocket.sendMessage(message)
}
</script>
4. 高级功能扩展
类型支持 (TypeScript)
如果你使用 TypeScript,可以添加类型定义:
// src/types/websocket.d.ts
declare module 'websocket' {
interface WebSocketMessage {
type: string
payload: any
}
type MessageListener = (message: WebSocketMessage) => void
export interface WebSocketService {
connect(url: string): void
disconnect(): void
sendMessage(message: WebSocketMessage | string): void
addMessageListener(callback: MessageListener): () => void
}
}
连接状态管理
可以在服务中添加连接状态跟踪:
class WebSocketService {
constructor() {
// ...其他代码
this.connectionState = 'disconnected' // 'connecting', 'connected', 'disconnected', 'error'
}
// 在 connect 方法中更新状态
connect(url) {
this.connectionState = 'connecting'
// ...其他代码
}
// 在 onopen 中更新状态
this.socket.onopen = () => {
this.connectionState = 'connected'
// ...其他代码
}
// 在 onclose 和 onerror 中更新状态
// ...
getConnectionState() {
return this.connectionState
}
}
自动重连策略
上面的示例已经包含了基本的重连逻辑,你可以根据需要扩展更复杂的重连策略,比如指数退避算法。
5. 使用建议
- 连接时机:通常在应用初始化时连接,但也可以根据需要延迟连接
- 错误处理:确保有良好的错误处理和重连机制
- 性能考虑:避免在消息监听器中执行耗时操作
- 安全性:对于敏感数据,考虑添加加密或认证机制
这种封装方式提供了全局的 WebSocket 管理,可以在应用的任何组件中轻松使用,同时保持了良好的可维护性和扩展性。