本文展示了Vue3和Vue2中WebSocket通信的实现方式。
Vue3版本使用@stomp/stompjs库,创建useWebSocket.js文件封装连接逻辑,包含初始化、连接/断开、自动重连等功能,并通过事件总线传递消息。
Vue2版本采用stompjs库,以mixin形式实现,包含订阅管理、心跳设置和重连机制。两者都支持消息订阅、自动重连和用户身份验证,Vue3版本更模块化,Vue2版本则以mixin形式提供复用功能。实现均包含错误处理和组件卸载时的连接清理。
vue3
先创建js文件,方便页面引入
//useWebSocket.js
import { ref, onUnmounted, computed } from "vue";
import { useStore } from "vuex";
import emitter from "@/utils/emitter.js";
import { Client } from "@stomp/stompjs";
export function useWebSocket() {
const store = useStore();
const client = ref(null);
const reconnectInterval = 5000;
const reconnectAttempts = ref(0);
const maxReconnectAttempts = 10;
const heartbeatOutgoing = 20000;
// 计算用户信息mixins.userInfo.value.user_id
const userInfo = computed(() => store.state.user.userInfo);
// 连接配置
const connectConfig = {
brokerURL: import.meta.env.VITE_APP_CLIENT_IP,
connectHeaders: {
login: import.meta.env.VITE_APP_CLIENT_ACCOUNT,
passcode: import.meta.env.VITE_APP_CLIENT_ACCOUNT_PASSCODE,
},
reconnectDelay: 5000,
heartbeatIncoming: 1000,
heartbeatOutgoing: heartbeatOutgoing,
};
// 初始化STOMP客户端
const initClient = () => {
client.value = new Client(connectConfig);
// 连接成功回调
client.value.onConnect = (frame) => {
if (frame.command == "CONNECTED") {
client.value.subscribe(
`/exchange/push_ur_exchange/${userInfo.value.user_id}`,
(frame) => {
// 消息处理
if (frame.body) {
emitter.emit("websocket-message", frame.body);
}
}
);
}
};
// 连接失败处理
client.value.onStompError = (frame) => {
console.log("报错:", frame);
};
};
// 连接方法
const connect = () => {
if (!client.value || !client.value.connected) {
initClient();
client.value.activate();
}
};
// 断开连接
const disconnect = () => {
if (client.value && client.value.connected) {
client.value.deactivate();
}
};
// 自动重连
const autoReconnect = () => {
if (
reconnectAttempts.value > 0 &&
reconnectAttempts.value <= maxReconnectAttempts
) {
connect();
}
};
// 组件卸载时自动断开
onUnmounted(() => {
disconnect();
});
return {
connect,
disconnect,
autoReconnect,
};
}
页面引用
const { connect, disconnect } = useWebSocket();
onMounted(() => {
connect();
// 监听消息
emitter.on("websocket-message", (data) => {
// 处理消息逻辑
state.messageNum = data
});
});
vue2
创建stomp.js
import Stomp from "stompjs";
import { mapGetters } from "vuex";
export const stompMixins = {
data() {
return {
client: null,
reconnectInterval: 5000, // 重连间隔时间
reconnectAttempts: 0, // 重连尝试计数
maxReconnectAttempts: 10, // 最大重连尝试次数
heartbeatIncoming: 0, // 服务端向客户端的心跳间隔(是接收频率)
heartbeatOutgoing: 20000, // 客户端向服务端的心跳间隔(是发送频率)
deviceTopic: null,
topic: null,
roomTopic: null,
largeScreenStatistics: null,
};
},
computed: {
...mapGetters(["userInfo"]),
},
beforeDestroy() {
this.disconnect(false);
},
created() {
this.connect(); // stomp连接mq
},
methods: {
shouldReconnect() {
this.reconnectAttempts++;
return this.reconnectAttempts <= this.maxReconnectAttempts;
},
disconnect(flag = true) {
let that = this;
/* 取消订阅 start */
if (that.deviceTopic) that.deviceTopic.unsubscribe();
if (that.topic) that.topic.unsubscribe();
if (that.roomTopic) that.roomTopic.unsubscribe();
if (that.largeScreenStatistics) that.largeScreenStatistics.unsubscribe();
/* 取消订阅 end */
if (that.client) {
that.client.disconnect(() => {
console.log("断开连接成功");
}); //断开连接
that.client = null; //清空client
}
if (!flag) return false;
if (that.shouldReconnect()) {
setTimeout(() => that.connect(), that.reconnectInterval);
} else {
that.$message.error("连接失败,超过最大重连次数"); //超过最大重连次数
}
},
onConnected: function (frame) {
let that = this;
that.client.heartbeat.outgoing = that.heartbeatOutgoing;
that.client.heartbeat.incoming = that.heartbeatIncoming;
// 订阅频道'
/* 消息推送 */
const roomTopic = "/exchange/room_push/" + that.userInfo.user_id;
that.roomTopic = that.client.subscribe(roomTopic, (frame) => {
if (frame.body) {
frame.body = frame.body.replace(
/:s*([0-9]{15,})s*(,?)/g,
': "$1" $2'
);
let data = JSON.parse(frame.body);
that.$btns.$emit("responseRoomCallback", data);
}
});
},
onFailed: function (frame) {
console.log("连接失败:" + frame);
this.disconnect();
},
responseCallback: function (frame) {
// 接收消息处理
if (frame.body) {
let data = JSON.parse(frame.body);
this.$notify({
title: "警告",
message: data.pushMessage,
type: "warning",
});
}
},
connect() {
// 初始化mqtt客户端,并连接mqtt服务
if (!this.client) {
this.reconnectAttempts = 0;
this.client = Stomp.client(process.env.VUE_APP_CLIENT_IP);
this.client.connect(
process.env.VUE_APP_CLIENT_ACCOUNT,
process.env.VUE_APP_CLIENT_ACCOUNT_PASSCODE,
this.onConnected,
this.onFailed,
"/"
);
}
},
},
};
引用:
import { stompMixins } from "./stomp.js";
export default {
mixins: [stompMixins],
provide() {
return {
index: this,
};
},
}
uniapp
先下载页面中引用的文件
资源免费下载

使用方法:
import WebSocket from '@/websocket/websocket-uni.js';
initWebSocket() {
const userInfo = uni.getStorageSync('userInfo')
// 连WebSocket
if (userInfo) {
WebSocket.init().then(client => {
client.subscribe(`/exchange/push_ur_exchange/${userInfo.user_id}`, function(res) {
console.log('返回数据', res);
});
}).catch(err => {
WebSocket.init()
});
}
},
如图所示:


897

被折叠的 条评论
为什么被折叠?



