谁还不会在vue3中使用MQTT?

1,805 阅读1分钟

并不是标题党,很多前端还真不会在vue中使用mqtt,所以为了方便各位查找相关资料有了以下简易教程,这里主要提供思路,欢迎各位进行交流

安装MQTT依赖

这里建议使用pnpm

pnpm add mqtt

创建sims-mqtt.d.ts(使用ts必须创建)

declare module "mqtt/dist/mqtt.min" {
  import MQTT from "mqtt";
  export = MQTT;
}

使用组合式封装MQTT

import * as mqtt from "mqtt/dist/mqtt.min";
import { Ref, ref, toRef, watch } from "vue";

export type MqttStatus = "OPEN" | "CONNECTING" | "CLOSED"

export interface UseMqttOptions {
  onConnected?: () => void,
  onDisconnected?: () => void,
  onError?: (error: Error | mqtt.ErrorWithReasonCode) => void,
  onMessage?: (topic: string, message: Buffer) => void,
  autoReconnect?: boolean | {
    retries?: number | (() => boolean)
    delay?: number
    onFailed?: Function
  },
  immediate?: boolean
}

export default function useMqtt(connection: Ref<mqtt.IClientOptions | undefined>, options: UseMqttOptions = {}) {
  const { onConnected, onDisconnected, onError, onMessage, immediate = true } = options
  const status = ref<MqttStatus>('CLOSED')
  const clientRef = ref<mqtt.MqttClient | undefined>()
  const connectionRef = toRef(connection)
  let explicitlyClosed = false
  let retried = 0
  let messageData: (string | Buffer)[] = []
  const _publishBuffer = (topic: string,) => {
    if (messageData.length && clientRef.value && status.value === "OPEN") {
      for (const buffer of messageData)
        clientRef.value.publish(topic, buffer)
      messageData = []
    }
  }
  const close = () => {
    if (!clientRef.value)
      return
    explicitlyClosed = true
    clientRef.value.end(true)
  }

  const send = (topic: string, message: string | Buffer, useBuffer = true) => {
    if (!clientRef.value || status.value !== "OPEN") {
      if (useBuffer)
        messageData.push(message)
      return
    }
    _publishBuffer(topic)
    clientRef.value.publish(topic, message)
    return true
  }

  const _init = () => {
    if (explicitlyClosed || typeof connectionRef.value === "undefined")
      return
    const { protocol, host, port, ...options } = connectionRef.value;
    const connectUrl = `${protocol}://${host}:${port}/mqtt`;
    const client = mqtt.connect(connectUrl, options)
    clientRef.value = client
    status.value = "CONNECTING"
    clientRef.value.on("connect", () => {
      status.value = "OPEN"
      onConnected?.()
    });
    clientRef.value.on("close", () => {
      status.value = "CLOSED"
      clientRef.value = undefined
      onDisconnected?.()
    })

    clientRef.value.on("error", (error) => {
      onError?.(error)
    });

    clientRef.value.on("message", (topic, message) => {
      onMessage?.(topic, message)
    });
  }

  const open = () => {
    close()
    explicitlyClosed = false
    retried = 0
    _init()
  }

  if (immediate)
    watch(connectionRef, open, { immediate: true })

  return {
    status,
    close,
    send,
    open,
    client: clientRef
  };
}

使用方法

const connection = ref<mqtt.IClientOptions>({
  protocol: "ws",
  host: "broker.emqx.io",
  port: 8083,
  clientId: "emqx_vue3_" + Math.random().toString(16).substring(2, 8),
  username: "emqx_test",
  password: "emqx_test",
  clean: true,
  connectTimeout: 30 * 1000,
  reconnectPeriod: 4000,
});

const { status, open, close } = useMqtt(connection, {
  onMessage(topic, message) {
    console.log(topic);
    console.log(message);
  },
});

github地址

HavocZhang/vue3-mqtt-client: vue3的mqtt连接示例 (github.com)

后续计划

  • 更优雅的实现订阅
  • 解决异常错误处理