05. 前端集成示例 (UniApp & JS)
1. UniApp 全局封装示例 (utils/socket.js)
javascript
export default class UniSocket {
constructor(url, token) {
this.url = `${url}/ws?token=${token}`;
this.socketTask = null;
this.isOpen = false;
this.reconnectCount = 0;
}
connect() {
this.socketTask = uni.connectSocket({ url: this.url });
this.socketTask.onOpen(() => {
this.isOpen = true;
this.reconnectCount = 0;
this.startHeartbeat();
});
this.socketTask.onMessage((res) => {
const data = JSON.parse(res.data);
uni.$emit('socketMessage', data);
});
this.socketTask.onClose(() => {
this.isOpen = false;
this.attemptReconnect();
});
}
send(data) {
if (this.isOpen) {
this.socketTask.send({ data: JSON.stringify(data) });
}
}
startHeartbeat() {
this.timer = setInterval(() => this.send({ cmd: 0, data: "ping" }), 30000);
}
attemptReconnect() {
if (this.reconnectCount < 5) {
setTimeout(() => {
this.reconnectCount++;
this.connect();
}, 5000);
}
}
}2. Vue 3 (Composition API) 完整示例
在 Vue 3 中,推荐使用 reactive 维护消息列表,并利用 onMounted 和 onUnmounted 管理生命周期。
2.1 封装核心 Hook (hooks/useSocket.js)
javascript
import { ref, onMounted, onUnmounted } from 'vue';
export function useSocket(url, token) {
const socket = ref(null);
const isConnected = ref(false);
const messages = ref([]);
const connect = () => {
socket.value = new WebSocket(`${url}/ws?token=${token}`);
socket.value.onopen = () => {
isConnected.value = true;
console.log('✅ WebSocket Connected');
};
socket.value.onmessage = (event) => {
const data = JSON.parse(event.data);
messages.value.push(data);
};
socket.value.onclose = () => {
isConnected.value = false;
// 可以在这里处理自动重连
};
};
const sendMessage = (receiverId, content) => {
if (socket.value && isConnected.value) {
socket.value.send(JSON.stringify({
cmd: "send_private_msg",
data: { receiverId, content, contentType: 'text' }
}));
}
};
onMounted(() => connect());
onUnmounted(() => socket.value?.close());
return { messages, isConnected, sendMessage };
}2.2 页面组件使用 (ChatComponent.vue)
vue
<script setup>
import { ref } from 'vue';
import { useSocket } from '@/hooks/useSocket';
const { messages, isConnected, sendMessage } = useSocket('ws://localhost:8060', 'your_token');
const inputText = ref('');
const handleSend = () => {
if (!inputText.value) return;
sendMessage('456', inputText.value); // 发送给用户 456
inputText.value = '';
};
</script>
<template>
<div class="chat-container">
<div class="status">状态: {{ isConnected ? '在线' : '离线' }}</div>
<div class="message-list">
<div v-for="(msg, index) in messages" :key="index" class="message-item">
<span class="sender">{{ msg.senderId }}:</span>
<span class="content">{{ msg.data?.content || msg.content }}</span>
</div>
</div>
<div class="input-box">
<input v-model="inputText" @keyup.enter="handleSend" placeholder="输入消息..." />
<button @click="handleSend">发送</button>
</div>
</div>
</template>3. UniApp 页面使用示例 (Vue 3 风格)
javascript
onLoad() {
// 监听消息
uni.$on('socketMessage', (msg) => {
if (msg.contentType === 'text') {
this.msgList.push(msg.data);
}
});
}
methods: {
handleSend() {
this.$socket.send({
cmd: "send_private_msg",
data: { receiverId: '456', content: 'Hello', contentType: 'text' }
});
}
}