并不是标题党,很多前端还真不会在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)
后续计划
- 更优雅的实现订阅
- 解决异常错误处理