UniApp ConnectSocket连接websocket - 详解
useSocket WebSocket 使用说明
项目地址
- Node.js 服务端项目: https://gitee.com/node-server_yarn/node_test_learn.git
- UniApp 客户端项目: https://gitee.com/uniapp_yarn/uniapp_socket_task.git
概述
useSocket
是一个基于 Vue 3 Composition API 的 WebSocket 封装 Hook,专为 UniApp 项目设计。它提供了完整的 WebSocket 连接管理、自动重连、心跳检测等功能,让您能够轻松地在 UniApp 项目中使用 WebSocket 进行实时通信。
功能特性
- ✅ 自动连接管理 - 支持自动连接和手动连接
- ✅ 自动重连机制 - 连接断开时自动重连,可配置重连次数和间隔
- ✅ 心跳检测 - 定期发送心跳包保持连接活跃
- ✅ 消息管理 - 自动解析和存储接收到的消息
- ✅ 状态监控 - 实时监控连接状态和重连次数
- ✅ 生命周期管理 - 组件卸载时自动断开连接
- ✅ 错误处理 - 完善的错误处理和回调机制
安装和导入
1. 克隆项目
首先克隆相关项目到本地:
# 克隆 Node.js 服务端项目
git clone https://gitee.com/node-server_yarn/node_test_learn.git
# 克隆 UniApp 客户端项目
git clone https://gitee.com/uniapp_yarn/uniapp_socket_task.git
2. 文件位置
将 useSocket.js
文件放置在项目的 src/hooks/
目录下。
3. 导入方式
import {useSocket
} from '@/hooks/useSocket';
基本使用
1. 最简单的使用方式
<template><view><text>连接状态: {{ isConnected ? '已连接' : '未连接'}}</text><button @click="sendMessage">发送消息</button></view></template><script setup>import { useSocket} from '@/hooks/useSocket';// 创建 WebSocket 连接const { isConnected, send, messages} = useSocket({url: 'ws://localhost:8080/ws',onMessage: (message) =>{console.log('收到消息:', message);}});// 发送消息const sendMessage = () =>{send({type: 'text',content: 'Hello WebSocket!'});};</script>
2. 完整配置示例
<template><view class="chat-container"><!-- 连接状态显示 --><view class="status-bar"><text>状态: {{ isConnected ? '已连接' : '未连接'}}</text><text v-if="reconnectCount > 0">重连次数: {{ reconnectCount}}</text></view><!-- 消息列表 --><scroll-view class="message-list" scroll-y><view v-for="message in messages" :key="message.timestamp" class="message-item"><text>{{ message.content}}</text></view></scroll-view><!-- 输入框 --><view class="input-area"><input v-model="inputText" placeholder="输入消息..." @confirm="handleSend" /><button @click="handleSend">发送</button></view></view></template><script setup>import { ref} from 'vue';import { useSocket} from '@/hooks/useSocket';const inputText = ref('');// 创建 WebSocket 连接const {isConnected,reconnectCount,messages,connect,disconnect,send,clearMessages} = useSocket({// WebSocket 服务器地址url: 'ws://localhost:8080/ws',// 最大重连次数maxReconnectCount: 5,// 重连间隔(毫秒)reconnectInterval: 3000,// 是否自动连接autoConnect: true,// 心跳间隔(毫秒)heartBeatInterval: 5000,// 连接成功回调onOpen: () =>{console.log('WebSocket 连接成功');uni.showToast({title: '连接成功',icon: 'success'});},// 接收消息回调onMessage: (message) =>{console.log('收到消息:', message);// 可以在这里处理不同类型的消息if (message.type === 'notification') {uni.showToast({title: message.content,icon: 'none'});}},// 连接错误回调onError: (error) =>{console.error('WebSocket 错误:', error);uni.showToast({title: '连接错误',icon: 'error'});},// 连接关闭回调onClose: (event) =>{console.log('WebSocket 连接关闭:', event);},// 达到最大重连次数回调onMaxReconnect: () =>{console.log('已达到最大重连次数');uni.showModal({title: '连接失败',content: '无法连接到服务器,请检查网络连接',showCancel: false});}});// 发送消息const handleSend = async () =>{if (!inputText.value.trim()) return;try {await send({type: 'text',content: inputText.value.trim(),timestamp: Date.now()});inputText.value = '';console.log('消息发送成功');} catch (error) {console.error('发送失败:', error);uni.showToast({title: '发送失败',icon: 'error'});}};// 手动连接const handleConnect = () =>{connect();};// 手动断开连接const handleDisconnect = () =>{disconnect();};// 清空消息const handleClearMessages = () =>{clearMessages();};</script>
API 参考
useSocket(options)
参数 (options)
参数名 | 类型 | 默认值 | 说明 |
---|---|---|---|
url | string | '' | WebSocket 服务器地址 |
maxReconnectCount | number | 5 | 最大重连次数 |
reconnectInterval | number | 3000 | 重连间隔(毫秒) |
autoConnect | boolean | true | 是否自动连接 |
heartBeatInterval | number | 5000 | 心跳间隔(毫秒) |
onOpen | function | - | 连接成功回调 |
onMessage | function | - | 接收消息回调 |
onError | function | - | 连接错误回调 |
onClose | function | - | 连接关闭回调 |
onMaxReconnect | function | - | 达到最大重连次数回调 |
返回值
属性名 | 类型 | 说明 |
---|---|---|
isConnected | ref(boolean) | 连接状态 |
reconnectCount | ref(number) | 当前重连次数 |
messages | ref(Array) | 消息列表 |
connect | function | 手动连接方法 |
disconnect | function | 断开连接方法 |
send | function | 发送消息方法 |
clearMessages | function | 清空消息方法 |
方法详解
connect()
手动建立 WebSocket 连接。
const {connect
} = useSocket({
url: 'ws://localhost:8080/ws'
});
connect();
disconnect()
手动断开 WebSocket 连接。
const {disconnect
} = useSocket({
url: 'ws://localhost:8080/ws'
});
disconnect();
send(data)
发送消息到服务器。
参数:
data
(string | object): 要发送的数据,可以是字符串或对象
返回值: Promise
// 发送字符串
await send('Hello World');
// 发送对象
await send({
type: 'message',
content: 'Hello World',
timestamp: Date.now(),
});
clearMessages()
清空消息列表。
const {clearMessages
} = useSocket({
url: 'ws://localhost:8080/ws'
});
clearMessages();
实际项目使用示例
聊天应用示例
<template><view class="chat-page"><!-- 聊天消息列表 --><scroll-view class="message-list" scroll-y :scroll-top="scrollTop"><view v-for="message in messages" :key="message.id" class="message-item"><view class="message-avatar"><image :src="message.avatar" mode="aspectFill" /></view><view class="message-content"><text>{{ message.content}}</text><text class="message-time">{{ message.timestamp}}</text></view></view></scroll-view><!-- 输入区域 --><view class="input-area"><inputv-model="inputText"placeholder="输入消息..."@confirm="handleSend":disabled="!isConnected"/><button@click="handleSend":disabled="!isConnected || !inputText.trim()">发送</button></view></view></template><script setup>import { ref, onMounted, nextTick} from 'vue';import { useSocket} from '@/hooks/useSocket';const inputText = ref('');const scrollTop = ref(0);// 创建 WebSocket 连接const { isConnected, messages, send} = useSocket({url: 'ws://localhost:8080/chat',onMessage: (message) =>{console.log('收到聊天消息:', message);// 自动滚动到底部nextTick(() =>{scrollToBottom();});},onOpen: () =>{console.log('聊天连接已建立');},onError: (error) =>{console.error('聊天连接错误:', error);uni.showToast({title: '连接失败',icon: 'error'});}});// 发送消息const handleSend = async () =>{if (!inputText.value.trim() || !isConnected.value) return;const message = {type: 'text',content: inputText.value.trim(),timestamp: new Date().toLocaleTimeString(),id: Date.now()};try {await send(message);inputText.value = '';} catch (error) {console.error('发送消息失败:', error);uni.showToast({title: '发送失败',icon: 'error'});}};// 滚动到底部const scrollToBottom = () =>{const query = uni.createSelectorQuery();query.select('.message-list').boundingClientRect();query.exec((res) =>{if (res[0]) {scrollTop.value = res[0].height;}});};onMounted(() =>{// 页面加载时自动连接console.log('聊天页面已加载');});</script>
实时通知示例
<template><view class="notification-page"><view class="status-indicator" :class="{ connected: isConnected }"><text>{{ isConnected ? '在线' : '离线'}}</text></view><view class="notification-list"><viewv-for="notification in messages":key="notification.id"class="notification-item"><text>{{ notification.content}}</text><text class="notification-time">{{ notification.timestamp}}</text></view></view></view></template><script setup>import { useSocket} from '@/hooks/useSocket';// 创建通知 WebSocket 连接const { isConnected, messages} = useSocket({url: 'ws://localhost:8080/notifications',onMessage: (notification) =>{console.log('收到通知:', notification);// 显示系统通知uni.showToast({title: notification.content,icon: 'none',duration: 3000});},onOpen: () =>{console.log('通知连接已建立');}});</script>
注意事项
1. 网络环境
- 确保 WebSocket 服务器地址正确且可访问
- 在真机调试时,需要使用实际的 IP 地址而非 localhost
2. 生命周期管理
- Hook 会在组件卸载时自动断开连接
- 如需在多个组件间共享连接,建议使用全局状态管理
3. 错误处理
- 建议为所有回调函数提供错误处理逻辑
- 网络异常时会有自动重连机制,但达到最大重连次数后需要手动处理
4. 性能优化
- 消息列表会持续增长,建议在适当时机调用
clearMessages()
清空 - 心跳间隔不宜过短,避免频繁的网络请求
5. 平台兼容性
- 本 Hook 基于 UniApp 的
uni.connectSocket
API - 支持所有 UniApp 支持的平台(H5、小程序、App)
完整源码
useSocket.js 源码
// composables/useWebSocket.js
import {ref, reactive, onUnmounted
} from 'vue';
export function useSocket(options = {
}) {
// 状态
const isConnected = ref(false);
const reconnectCount = ref(0);
const messages = ref([]);
const socketTask = ref(null);
// 配置
const config = reactive({
url: options.url || '',
maxReconnectCount: options.maxReconnectCount || 5, // 最大重连次数
reconnectInterval: options.reconnectInterval || 3000, // 重连间隔
autoConnect: options.autoConnect !== false, // 自动连接
heartBeatInterval: options.heartBeatInterval || 5000, // 心跳间隔
...options,
});
// 心跳计时器
let heartBeatTimer = null;
// 连接 WebSocket
const connect = () =>
{
if (socketTask.value) {
disconnect();
}
// console.log('正在连接 WebSocket...');
socketTask.value = uni.connectSocket({
url: config.url,
header: {
'content-type': 'application/json',
},
success: () =>
{
console.log('[WebSocket] 连接创建成功');
},
fail: (err) =>
{
console.error('[WebSocket] 连接创建失败', err);
options.onError?.(err);
handleReconnect();
},
});
bindEvents();
};
// 绑定事件
const bindEvents = () =>
{
if (!socketTask.value) return;
socketTask.value.onOpen(() =>
{
console.log('[WebSocket] 连接已打开');
isConnected.value = true;
reconnectCount.value = 0;
options.onOpen?.();
startHeartBeat();
});
socketTask.value.onMessage((res) =>
{
const message = parseMessage(res.data);
options.onMessage?.(message);
messages.value.push(message);
});
socketTask.value.onError((err) =>
{
console.error('[WebSocket] 连接错误:', err);
isConnected.value = false;
options.onError?.(err);
handleReconnect();
});
socketTask.value.onClose((res) =>
{
console.log('[WebSocket] 连接已关闭', res);
isConnected.value = false;
options.onClose?.(res);
stopHeartBeat();
});
};
// 发送消息
const send = (data) =>
{
if (!isConnected.value || !socketTask.value) {
throw new Error('WebSocket 未连接');
}
const message = typeof data === 'string' ? data : JSON.stringify(data);
return new Promise((resolve, reject) =>
{
socketTask.value.send({
data: message,
success: () =>
{
console.log('消息发送成功');
resolve();
},
fail: (err) =>
{
console.error('消息发送失败', err);
reject(err);
},
});
});
};
// 断开连接
const disconnect = () =>
{
if (socketTask.value && socketTask.value.readyState === 1) {
socketTask.value.close();
socketTask.value = null;
}
isConnected.value = false;
stopHeartBeat();
};
// 重连机制
const handleReconnect = () =>
{
if (reconnectCount.value >= config.maxReconnectCount) {
console.log('[WebSocket] 已达到最大重连次数');
options.onMaxReconnect?.();
return;
}
reconnectCount.value++;
console.log(`[WebSocket] 尝试第 ${reconnectCount.value
} 次重连...`);
setTimeout(() =>
{
connect();
}, config.reconnectInterval);
};
// 解析消息
const parseMessage = (data) =>
{
try {
return JSON.parse(data);
} catch {
return {
type: 'text',
content: data,
timestamp: Date.now(),
};
}
};
// 心跳检测
const startHeartBeat = () =>
{
if (!config.heartBeatInterval) return;
stopHeartBeat();
heartBeatTimer = setInterval(() =>
{
if (isConnected.value) {
send({
type: 'ping',
timestamp: Date.now(),
}).catch((err) =>
{
console.error('[WebSocket] 心跳发送失败', err);
});
}
}, config.heartBeatInterval);
};
const stopHeartBeat = () =>
{
if (heartBeatTimer) {
clearInterval(heartBeatTimer);
heartBeatTimer = null;
}
};
// 清空消息
const clearMessages = () =>
{
messages.value = [];
};
// 自动连接
if (config.autoConnect && config.url) {
connect();
}
// 组件卸载时清理
onUnmounted(() =>
{
disconnect();
});
return {
// 状态
isConnected,
reconnectCount,
messages,
// 方法
connect,
disconnect,
send,
clearMessages,
};
}
总结
useSocket
Hook 为 UniApp 项目提供了完整的 WebSocket 解决方案,具有以下优势:
- 开箱即用 - 简单的 API 设计,快速上手
- 功能完整 - 包含连接管理、重连、心跳等完整功能
- 错误处理 - 完善的错误处理和回调机制
- 性能优化 - 自动清理和生命周期管理
- 易于扩展 - 基于 Vue 3 Composition API,易于扩展和定制
通过本说明文档,您应该能够快速在项目中使用 useSocket
实现 WebSocket 功能。如有任何问题,请参考示例代码或查看源码实现。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/918787.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!相关文章
《etcd库——键值存储系统》 - 教程
《etcd库——键值存储系统》 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco…
有一个函数只会返回0和1,且返回0和返回1的概率不等。要求只能通过这个函数生成一个等概率返回0和1的函数
有一个函数只会返回0和1,且返回0和返回1的概率不等。要求只能通过这个函数生成一个等概率返回0和1的函数题目分析这个函数只会生成0和1,虽然不等概率,但是如果我们roll两次,只记录结果是(0,1)和(1,0)的这两种情况。…
AI智能体开发实战:17种核心架构模式详解与Python代码实现
在构建一个大规模 AI 系统时,我们其实就是在把不同的“智能体设计模式(agentic design patterns)”组合起来。不管系统多复杂都可以拆解成有限的几种"设计模式"。这些模式各有各的用法——有的专门负责思…
代码随想录算法训练营第十天 | 232. 用栈实现队列、225. 用队列实现栈、20. 有效的括号、删除字符串中的所有相邻重复项
都很简单不赘述type MyQueue struct {StackinTop intStackOutTop intStackIn []intStackOut []int
}func Constructor() MyQueue {StackIn := make([]int,0)StackOut := make([]int,0)return MyQueue{StackinTop: 0,St…
文书写作网站百度收录查询api
精讲部分,主要是对Transformer的深度理解方便日后从底层逻辑进行创新,对于仅应用需求的小伙伴可以跳过这一部分,不影响正常学习。 1. 残差模块 何凯明在2015年提出的残差网络(ResNet),Transformer在2016年…
深度学习周报(9.15~9.21) - 实践
pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …
关于“悬荡悟空”决策机制的简要技术说明
关于“悬荡悟空”决策机制的简要技术说明
“悬荡悟空”是一种尚处于构想阶段的智能决策机制,其核心在于尝试使系统具备在复杂情境中进行多路径因果并行推演与价值权衡的能力。
该机制在极端场景(如自动驾驶面临的突发…
最小二乘问题详解1:线性最小二乘
最小二乘法通过最小化误差平方和来寻找数据的最佳拟合模型,其核心原理在线性情况下可通过代数或几何方式推导出正规方程,揭示了参数估计与向量空间正交投影之间的深刻联系。1. 引言
最小二乘可以说是现代科学与工程的…
完整教程:分布式ID解决方案
pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …
20250926周五日记
20250926周五日记vision.middlebury.edu/stereo/data 计算机视觉领域的权威评测平台,可下载深度标签数据集。
https://github.com/googleinterns/IBRNet
https://github.com/VITA-Group/GNT?tab=readme-ov-file
http…
工程监理行业多模态视觉大模型系统,打造工地行业全场景的监理智能生态
建筑工程监理行业在面对复杂多变的施工现场时,传统的监理方式面临诸多挑战。文明施工监管困难重重,难以实时监督施工现场的围挡是否达标、垃圾是否及时清运、施工道路是否硬化等;基坑风险排查依靠人工,效率低下且难…
济南哪家网站技术比较高老房装修
【网络取证箱】网络取证在线分析工具箱
在线网站查询工具箱,没什么介绍的,所见即所得,在本文档里补充了其它一些网络安全资源,请忽用于非法活动,仅供学习研究—【蘇小沐】
(一)Whois查询
主要…
淄博网站制作托管优化泉州网站制作专业
速率
指快慢 比特:1/0(1位比特)
速率:单位换算1000倍(小写b),如,b/s比特每秒;kb/s千比特每秒 存储容量:单位换算1024倍(大写B),如B字节…
网站团队建设wto最新新闻
网络编程主要的内容是: 1.TCP网络编程 2.http服务 3.rpc服务 4.websocket服务 一、rpc RPC 框架----- 远程过程调用协议RPC(Remote Procedure Call Protocol)-----允许像调用本地服务一样调用远程服务。 RPC是指远程过程调用,也就是说两台服…
数据结构——静态链表(c语言笔记) - 实践
数据结构——静态链表(c语言笔记) - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "…
完整教程:【鸿蒙心迹】摸蓝图,打地基
完整教程:【鸿蒙心迹】摸蓝图,打地基pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Mon…
深圳专业网站制作网站推广方法 优帮云
戳蓝字“CSDN云计算”关注我们哦!尽管最近新闻铺天盖地的“寒冬说”,由于我多年身处在稳定的大公司里,并没有太多的危机感。昨天大伙一起讨论年会表演什么节目,你演宁采臣,他男扮女装演小倩,大胖就演宁采臣…