MQTT状态管理Vuex全局状态管理
1.uniapp集成MQTT协议,参考我的文章:https://www.cnblogs.com/zhangyouwu/p/19439905
2.创建store/index.js
// 页面路径:store/index.js import { createStore } from 'vuex' const store = createStore({ state:{//存放状态 "xcx_zt":0,//程序是否在线 "m_zt":0,//设备是否在线 'm_id':'',//设备ID }, mutations: { chang_xcx_zt(state, n) { state.xcx_zt = n }, chang_m_zt(state, n) { state.m_zt = n }, chang_m_id(state, n) { state.m_id = n }, } }) export default store
3.在 main.js 中导入文件,主要这2句

import store from './store'
app.use(store)
4.修改mqtt.js
import mqtt from 'mqtt/dist/mqtt.min' import store from '@/store/index.js' // MQTT 配置(根据实际服务端修改) const MQTT_CONFIG = { // 不同端的连接协议: // H5: ws://xxx:8083/mqtt 或 wss://xxx:8084/mqtt // 微信小程序: wxs://xxx:8084/mqtt(需配置域名白名单) // App: tcp://xxx:1883(需配置网络权限) host: 'wxs://xxx:8084/mqtt', // host: 'ws://xxx:8083/mqtt', clientId: `wine-${Math.random().toString(16).substr(2, 8)}`, // 唯一客户端ID username: 'zyw', // 服务端认证用户名(无则留空) password: 'zyw123456', // 服务端认证密码(无则留空) keepalive: 60, // 心跳间隔(秒) reconnectPeriod: 5000, // 重连间隔(毫秒) clean: true // 清除会话(true:断开后不保留订阅) } // 全局 MQTT 客户端实例 let client = null // 消息回调函数(供页面监听) let messageCallback = null /** * 连接 MQTT 服务器 * @param {Function} callback 消息接收回调 (topic, message) => {} */ export function connectMQTT(callback) { // 保存消息回调 messageCallback = callback // 已连接则直接返回 if (client && client.connected){ store.commit('chang_xcx_zt', 1)//在线 return false; } // 创建连接 client = mqtt.connect(MQTT_CONFIG.host, { clientId: MQTT_CONFIG.clientId, username: MQTT_CONFIG.username, password: MQTT_CONFIG.password, keepalive: MQTT_CONFIG.keepalive, reconnectPeriod: MQTT_CONFIG.reconnectPeriod, clean: MQTT_CONFIG.clean }) // 连接成功回调 client.on('connect', () => { console.log('MQTT 连接成功:', MQTT_CONFIG.clientId); if(MQTT_CONFIG.clientId){ store.commit('chang_xcx_zt', 1)//在线 if (messageCallback) { var p_obj={}; var p_data={}; p_data.keyword="connect"; p_data.clientId=MQTT_CONFIG.clientId; p_data.msg="MQTT 连接成功"; p_obj.code=1; p_obj.data=p_data; messageCallback(p_obj) // 转字符串便于处理 } } }) // 接收消息回调 client.on('message', (topic, message) => { console.log(`收到消息1:topic=${topic}, message=${message.toString()}`) if (messageCallback) { messageCallback(topic, message.toString()) // 转字符串便于处理 } }) // 连接错误回调 client.on('error', (error) => { console.error('MQTT 连接错误:', error) store.commit('chang_xcx_zt', 0)//离线 if (messageCallback) { var p_obj={}; var p_data={}; p_data.keyword="error"; p_data.error=error; p_data.msg="MQTT 连接错误"; p_obj.code=1; p_obj.data=p_data; messageCallback(p_obj) // 转字符串便于处理 } }) // 断开连接回调 client.on('close', () => { console.log('MQTT 连接断开'); store.commit('chang_xcx_zt', 0)//离线 if (messageCallback) { var p_obj={}; var p_data={}; p_data.keyword="close"; p_data.msg="MQTT 连接断开"; p_obj.code=1; p_obj.data=p_data; messageCallback(p_obj) // 转字符串便于处理 } }) // 重连回调 client.on('reconnect', () => { console.log('MQTT 正在重连...') store.commit('chang_xcx_zt', 0)//离线 if (messageCallback) { var p_obj={}; var p_data={}; p_data.keyword="reconnect"; p_data.msg="MQTT 正在重连"; p_obj.code=1; p_obj.data=p_data; messageCallback(p_obj) // 转字符串便于处理 } }) } /** * 断开 MQTT 连接 */ export function disconnectMQTT(callback) { if (client && client.connected) { // 保存消息回调 messageCallback = callback client.end() client = null console.log('MQTT 主动断开连接') store.commit('chang_xcx_zt', 0)//离线 if (messageCallback) { var p_obj={}; var p_data={}; p_data.keyword="disconnect"; p_data.msg="MQTT 主动断开连接"; p_obj.code=1; p_obj.data=p_data; messageCallback(p_obj) // 转字符串便于处理 } } } /** * 订阅 MQTT 主题 * @param {String|Array} topic 主题(单个字符串或数组) * @param {Number} qos 服务质量(0/1/2,默认0) */ export function subscribeMQTT(topic, qos = 0) { if (!client || !client.connected) { console.error('MQTT 未连接,无法订阅') return } client.subscribe(topic, { qos }, (error) => { if (error) { console.error(`订阅主题 ${topic} 失败:`, error) } else { console.log(`订阅主题 ${topic} 成功`) } }) } /** * 发布 MQTT 消息 * @param {String} topic 主题 * @param {String|Object} message 消息内容(对象会转为JSON字符串) * @param {Number} qos 服务质量(0/1/2,默认0) */ export function publishMQTT(topic, message, qos = 0) { if (!client || !client.connected) { console.error('MQTT 未连接,无法发布消息') return } // 统一转为字符串 const msg = typeof message === 'object' ? JSON.stringify(message) : message client.publish(topic, msg, { qos }, (error) => { if (error) { console.error(`发布消息到 ${topic} 失败:`, error) } else { console.log(`发布消息到 ${topic} 成功:`, msg) } }) } /** * 取消订阅 MQTT 主题 * @param {String|Array} topic 主题(单个字符串或数组) */ export function unsubscribeMQTT(topic) { if (!client || !client.connected) { console.error('MQTT 未连接,无法取消订阅') return } client.unsubscribe(topic, (error) => { if (error) { console.error(`取消订阅 ${topic} 失败:`, error) } else { console.log(`取消订阅 ${topic} 成功`) } }) } mqtt.js
5.创建在线组件/components/online/online.vue,其中2个getApp().add_log方法是上传连接日志到服务器,请自行删除
<template>
<view>
<view class="topfixed">
<view class="topfixed_content">
<!-- <view :style="'height:'+statusBarHeight+'px;'"></view> -->
<view class="topNavBox">
<view class="leftBtnBox">
<view class="gobackBox color-white font-28">
<view>设备:</view>
<block v-if="m_zt==1">
<view class="flex">
<u-icon name="pause-circle-fill" color="#00AA59" size="18"></u-icon>
<view class="ml6">在线</view>
</view>
</block>
<block v-else>
<view class="flex">
<u-icon name="minus-circle-fill" color="#ff0000" size="18"></u-icon>
<view class="ml6">离线</view>
</view>
</block>
</view>
</view>
</view>
<view class="topNavBox">
<view class="leftBtnBox">
<view class="gobackBox color-white font-28">
<view>程序:</view>
<block v-if="xcx_zt==1">
<view class="flex" @click="disconnect">
<u-icon name="pause-circle-fill" color="#00AA59" size="18"></u-icon>
<view class="ml6">在线</view>
</view>
</block>
<block v-else>
<view class="flex" @click="connect">
<u-icon name="minus-circle-fill" color="#ff0000" size="18"></u-icon>
<view class="ml6">离线</view>
</view>
</block>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { connectMQTT, subscribeMQTT, publishMQTT, disconnectMQTT } from '@/common/mqtt.js'
export default {
name:"online",
props: {
},
data() {
return {
statusBarHeight: uni.getSystemInfoSync ().statusBarHeight,//状态栏高度
receiveMessage: '' // 接收的消息
}
},
computed: {
//程序:0离线 1在线
xcx_zt() {
return this.$store.state.xcx_zt;
},
//设备:0离线 1在线
m_zt() {
return this.$store.state.m_zt;
}
},
methods: {
// 连接MQTT
connect() {
var _this=this;
connectMQTT((res) => {
//console.log(res);
if(res.code==1){
getApp().add_log(res.data).then((resolve, reject) => {//创建日志
//console.log(resolve);
if(resolve.code==1){
}
})
}
// var str=`主题:${topic},内容:${message}`;
// console.log(str)
// // 监听接收的消息
// _this.receiveMessage = `主题:${topic},内容:${message}`
})
},
// 订阅主题(示例:/uni-app/test)
subscribe() {
subscribeMQTT('/uni-app/test')
},
// 发布消息(示例:向/uni-app/test发布消息)
publish() {
publishMQTT('/uni-app/test', {
content: 'Hello Uni-app MQTT',
time: new Date().toLocaleString()
})
},
// 断开连接
disconnect() {
var _this=this;
disconnectMQTT((res) => {
if(res.code==1){
getApp().add_log(res.data).then((resolve, reject) => {//创建日志
//console.log(resolve);
if(resolve.code==1){
this.receiveMessage = ''
}
})
}
});
}
}
}
</script>
<style>
.topfixed{
position: fixed;
top: 0;
left: 0;
z-index: 20;
/* // background-color: #fff; */
width: 100%;
padding: 0 20rpx;
box-sizing: border-box;
}
.topfixed_content{
width: 100%;
}
/* #ifdef H5 */
.topfixed_content{
max-width: 420px;
margin: auto;
}
/* #endif */
.topfixed .topNavBox{
width:100%;
height:40px;
display: flex;
padding: 4px 0;
box-sizing: border-box;
}
.topfixed .topNavBox .leftBtnBox{
flex: none;
background-color: rgba(0,0,0,0.7);
display: flex;
height: 32px;
border-radius: 100px;
}
.topfixed .topNavBox .leftBtnBox .gobackBox{
padding: 0 25rpx;
display: flex;
align-items: center;
position: relative;
}
.topfixed .topNavBox .leftBtnBox .gobackBox.goHomeBox::before{
content: '';
width: 1px;
height: 20px;
position: absolute;
left: 0;
top: 50%;
margin-top: -10px;
background-color: #fff;
}
</style>
6.App.vue内容,其中add_log方法是上传连接日志到服务器,请自行删除
<script> import { connectMQTT, subscribeMQTT, publishMQTT, disconnectMQTT } from '@/common/mqtt.js' export default { onLaunch: function() { console.log('App Launch') // 初始化MQTT连接(全局生效) //this.initMqtt(); }, onShow: function() { console.log('App Show') // 应用切前台时检查连接,断开则重连 var xcx_zt = this.$store.state.xcx_zt; //console.log("cccc",xcx_zt) if (!xcx_zt) { this.initMqtt() } }, onHide: function() { //console.log('App Hide'); // 应用切后台:可选断开连接(根据业务需求) this.disMqtt(); }, methods:{ // 连接MQTT initMqtt() { console.log("eee") var _this=this; connectMQTT((res) => { console.log("ffff") if(res.code==1){ //创建日志 this.add_log(res.data).then((resolve, reject) => { }) } }) }, // 断开连接MQTT disMqtt() { console.log("dddd") var _this=this; disconnectMQTT((res) => { if(res.code==1){ //创建日志 this.add_log(res.data).then((resolve, reject) => { }) } }); }, //连接日志 async add_log(params){ var _this=this; return new Promise((resolve, reject) => { let p_obj={}; p_obj.code=0; p_obj.msg="操作失败"; let user_info = uni.getStorageSync('user_info'); let post_obj={}; post_obj.user_id=user_info.id; //小程序 // #ifdef MP-WEIXIN let openid=uni.getStorageSync('openid'); post_obj.openid=openid; // #endif post_obj.keyword=params.keyword; post_obj.params=params; uni.$u.api.mqtt_log(post_obj).then(res => { if(res.code==1){ p_obj.code=1; p_obj.msg=res.msg; resolve(p_obj); return false; }else{ p_obj.code=0; p_obj.msg=res.msg; resolve(p_obj); return false; } }) }) }, } } </script> <style lang="scss"> /*每个页面公共css */ </style>
7.创建测试文件/pages/index/index.vue,其中tabBar是我自定义的菜单组件,请自行删除
<template>
<view class="">
<view>
<online></online>
</view>
<map style="width: 100%; height: 300px;" :latitude="latitude" :longitude="longitude" :style="'height:'+windowHeight*2+'rpx;'">
</map>
<view>
<tabBar :pageIndex="100" :textType="1" @toTab="toTab"></tabBar>
</view>
</view>
</template>
<script>
import tabBar from '@/components/tabBar/tabBar.vue';
import online from '@/components/online/online.vue';//是否在线
export default {
components: {
tabBar,
online,//是否在线
},
data() {
return {
windowHeight : uni.getSystemInfoSync().windowHeight,//屏幕高度
title: 'Hello',
latitude:'34.259428',
longitude:'108.947040',
}
},
onLoad() {
// 隐藏默认菜单栏
uni.hideTabBar({animation: false});
},
onShow() {
// 隐藏默认菜单栏
uni.hideTabBar({animation: false});
},
methods: {
//菜单跳转
toTab(item){
//console.log(item);
var id =item.id;//1购买记录 2扫码饮酒 3我的
//扫码饮酒
if(id==1){
uni.navigateTo({
url:'/pages_a/order/list',
// url:'/pages_a/pour/pouring'
})
}else if(id==2){
uni.navigateTo({
url:'/pages/sao/index?m_id=1'
//url:'/pages/sao/index'
})
// uni.scanCode({
// scanType: ['qrCode'], //只支持二维码
// onlyFromCamera: true,
// success: function(res) {
// console.log('条码类型:' + res.scanType);
// console.log('条码内容:' + res.result);
// }
// });
}else if(id==3){
uni.switchTab({
url:'/pages/my/index'
})
}
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>
结果


浙公网安备 33010602011771号