在多页面场景中,使用 Pinia 来共享 WebSocket 消息非常适合,因为 Pinia 是全局的状态管理工具,所有页面或组件都可以访问同一个状态,实现消息共享。
实现思路
- 通过 Pinia 管理 WebSocket 实例及其数据: 将 WebSocket 的逻辑封装在一个 Pinia Store 中。
- 所有页面或组件订阅相同的 Pinia Store: 通过 Pinia 的状态更新,页面共享数据。
- 集中式消息处理: 将消息解析和分发逻辑放在 Store 中,避免重复处理。
实现步骤
1. 创建 WebSocket Store
创建一个用于管理 WebSocket 的 Pinia Store,比如 stores/websocket.js
:
import { defineStore } from 'pinia';
export const useWebSocketStore = defineStore('websocket', {
state: () => ({
ws: null, // WebSocket 实例
isConnected: false, // WebSocket 连接状态
message: null, // 最新收到的消息
messages: [], // 消息列表(可选)
}),
actions: {
connect(url) {
if (this.ws) {
console.warn('WebSocket already connected.');
return;
}
this.ws = new WebSocket(url);
this.ws.onopen = () => {
this.isConnected = true;
console.log('WebSocket connected');
};
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
this.message = data; // 更新最新消息
this.messages.push(data); // 保存历史消息(可选)
};
this.ws.onclose = () => {
this.isConnected = false;
this.ws = null;
console.error('WebSocket closed. Reconnecting...');
setTimeout(() => this.connect(url), 3000); // 自动重连
};
this.ws.onerror = (err) => {
console.error('WebSocket error:', err);
};
},
sendMessage(data) {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(data));
} else {
console.error('WebSocket is not open.');
}
},
close() {
if (this.ws) {
this.ws.close();
this.ws = null;
this.isConnected = false;
}
},
},
});
2. 在应用启动时初始化 WebSocket
在应用的主入口文件 main.js
中初始化 WebSocket:
// main.js
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';
import { useWebSocketStore } from './stores/websocket';
const app = createApp(App);
const pinia = createPinia();
app.use(pinia);
// 初始化 WebSocket
const wsStore = useWebSocketStore();
wsStore.connect('wss://your-websocket-url');
app.mount('#app');
3. 在页面或组件中使用 WebSocket 数据
每个页面或组件可以直接访问 WebSocketStore
,实时共享最新的消息和状态。
<template>
<div>
<h1>WebSocket Data</h1>
<p>Connection Status: {{ isConnected ? 'Connected' : 'Disconnected' }}</p>
<p>Latest Message: {{ message }}</p>
<ul>
<li v-for="(msg, index) in messages" :key="index">
{{ msg }}
</li>
</ul>
<button @click="sendPing">Send Ping</button>
</div>
</template>
<script>
import { useWebSocketStore } from '@/stores/websocket';
export default {
setup() {
const wsStore = useWebSocketStore();
const sendPing = () => {
wsStore.sendMessage({ type: 'ping', timestamp: Date.now() });
};
return {
isConnected: wsStore.isConnected,
message: wsStore.message,
messages: wsStore.messages,
sendPing,
};
},
};
</script>
4. 支持多页面共享的关键点
- Pinia 是全局共享的: 每个页面访问的是同一个
WebSocketStore
实例,因此状态(message
、messages
等)始终一致。 - 组件不需重复创建 WebSocket: 通过在
main.js
中初始化 WebSocket,确保整个应用只创建一个 WebSocket 实例。 - 实时数据同步: 当 Store 的
message
更新时,所有订阅页面会立即响应。
优化建议
-
消息分发: 如果 WebSocket 返回的数据需要分发到不同模块,可以在
onmessage
中根据数据类型调用其他 Store 的方法。例如:const someStore = useSomeStore(); this.ws.onmessage = (event) => { const data = JSON.parse(event.data); if (data.type === 'notification') { someStore.addNotification(data); } };
-
使用持久化插件: 如果需要在页面刷新时保留历史消息(
messages
),可以使用 Pinia 的持久化插件(如pinia-plugin-persist
)。import piniaPluginPersistedState from 'pinia-plugin-persistedstate'; const pinia = createPinia(); pinia.use(piniaPluginPersistedState);
-
性能优化: 对频繁更新的消息进行节流或防抖处理,避免组件过度渲染。
这样,每个页面都可以方便地共享和实时获取 WebSocket 的消息!