需要先安装一些依赖
npm install mqtt@3.0.0 uuid
mqttStore.js
// todo 在配置中增加对应 mqtt 地址
import {mqttUrl} from "@/config";
// 必须是 dist/mqtt.js,不能是 'mqtt'
import mqtt from 'mqtt/dist/mqtt';
import {v4} from "uuid";
import modal from '@/plugins/modal'
const options = {
// 注意开发中 h5 中因为每次热更新都会生成一个新的 clientid,会生成多个连接
clientId: v4(),
connectTimeout: 10000,
clean: true,
username: '123456',
password: '',
reconnectPeriod: 1000,
}
// #ifdef MP-WEIXIN||APP-PLUS
const deviceInfo = uni.getDeviceInfo()
options.clientId = 'app-' + deviceInfo.deviceId
// #endif
console.log('mqtt options', options)
const mqttStore = {
namespaced: true,
state: {
client: undefined,
isConnected: false, // 当前连接状态
},
getters: {
getClient(state) {
return state.client
},
getIsConnected(state) {
return state.isConnected
},
},
mutations: {
setClient(state, value) {
state.client = value
},
setIsConnected(state, value) {
state.isConnected = value
},
setClientReconnectPeriod(state, value) {
state.client.reconnectPeriod = value
}
},
actions: {
connect({state, commit}) {
return new Promise((resolve, reject) => {
if (state.isConnected) {
resolve(state.client)
return
}
// 如果已有 client,不重复生成,直接调用重连方法,监听和订阅还会保留
if (state.client) {
state.client.reconnect()
return
}
let client
// #ifdef H5
console.log('H5 mqtt connect');
client = mqtt.connect('ws://' + mqttUrl, options)
// #endif
// #ifdef MP-WEIXIN||APP-PLUS
console.log('app mqtt connect');
// uni-app app-plus 仅支持 wx:// 的,不可以用 mqtt://
client = mqtt.connect('wx://' + mqttUrl, options)
// #endif
commit('setClient', client)
client
.on('connect', (res) => {
console.log("mqtt 连接成功", client.connected)
commit('setIsConnected', true)
resolve(client)
})
.on('message', function (topic, message) {
console.log('mqtt message' + topic + message.toString())
})
.on('reconnect', function (topic, message) {
console.log("mqtt 重连")
})
.on('close', function () {
console.log('mqtt close');
commit('setIsConnected', false)
})
.on('disconnect', () => {
console.log('mqtt disconnect');
commit('setIsConnected', false)
})
.on('error', function (e) {
console.log('mqtt error', e);
})
})
},
reconnect({state}) {
if (state.isConnected) return
state.client.reconnect()
},
// 关闭连接,不会再重连
end({state, commit}) {
if (!state.client) return
console.log('mqtt 断开连接');
state.client.end()
commit('setIsConnected', false)
// 关闭重连
commit('setClientReconnectPeriod', 0)
},
subscribe({state}, topic) {
return new Promise((resolve, reject) => {
if (!state.isConnected) {
console.log('未建立连接, 订阅失败');
reject()
return
}
state.client.subscribe(topic, (err) => {
if (!err) {
console.log("mqtt 订阅成功")
resolve()
} else {
console.log("mqtt 订阅失败")
reject(err)
}
})
})
},
sendMessage({state}, {topic, message}) {
if (!state.isConnected) {
console.log('未建立连接');
modal.msg('未建立连接')
return
}
state.client.publish(topic, message)
},
onMessage({state}, callback) {
if (!state.isConnected) {
console.log('未建立连接');
modal.msg('未建立连接')
return
}
state.client.on('message', callback)
},
},
}
export default mqttStore
在 vuex 的 store/index.js 引入 mqtt: mqttStore 后就可以在页面中使用
<template>
<uni-section title="mqtt test" type="line">
<view class="content">
<view>isConnected: {{ isConnected }}</view>
<button @click="connect" type="primary">建立连接</button>
<uni-section title="发送消息">
<button @click="send" type="primary">发送消息</button>
</uni-section>
<button @click="end" type="primary">结束连接</button>
<button @click="clear" type="primary">清空Logs</button>
<view class="log">
<view v-for="(log,index) in logs" class="" :key="index">
{{ log }}
</view>
</view>
</view>
</uni-section>
</template>
<script>
import {mapGetters} from "vuex";
export default {
name: "mqtt-test",
data() {
return {
logs: [],
}
},
computed: {
...mapGetters({
'client': 'mqtt/getClient',
'isConnected': 'mqtt/getIsConnected',
})
},
mounted() {
this.connect()
},
methods: {
async connect() {
await this.$store.dispatch('mqtt/connect')
await this.$store.dispatch('mqtt/subscribe', 'test')
this.$store.dispatch('mqtt/onMessage', (topic, message) => {
this.logs.push(topic + ', ' + message.toString())
})
},
send() {
this.$store.dispatch('mqtt/sendMessage', {
topic: 'test',
message: 'client send test message'
})
},
end() {
this.$store.dispatch('mqtt/end')
},
clear() {
this.logs = []
}
}
}
</script>
测试页面效果