uni-app封装mqtt到vuex的store

616 阅读1分钟

需要先安装一些依赖

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>

测试页面效果

image.png