vue3+ts 二次封装mqtt 发布订阅模式

2,242 阅读1分钟

话不多说,直接上代码

1.使用

import Mqtt from '@/utils/mqtt/index'
const clientId = 'mqttjs_' + Math.random().toString(16).substr(2, 8)
app.use(Mqtt, 'ws://47.xxx.14.180:8083/mqtt', {
    keepalive: 60,
    clientId: clientId,//根据自己业务来
    protocolId: 'MQTT',
    protocolVersion: 4,
    clean: true,
    username: '',
    password: '',
    reconnectPeriod: 1000,
    connectTimeout: 30 * 1000,
    will: ''
  })
  
  在setup方法中 '/ksjk/web/datashow/alarm' 是订阅主题地址
  Reflect.set(proxy?.$options as Object, 'mqtts', {
  '/ksjk/web/datashow/alarm': (topic: string, payload: Buffer) => {
        try {
            let data = JSON.parse(payload.toString());
            console.log(`rx: ${payload}=>${data.type}`);
        } catch (err) {
           console.log(err);
        }
    },
});

2.进入正题

utils/mqtt/index.ts

import * as mqtt from 'mqtt/dist/mqtt.min';
import Emitter from "./Emitter";
import { App } from "vue";
export type MqttConnOpt = mqtt.IClientOptions

export class MQTT {
  mqClient!: mqtt.MqttClient
  private readonly store: any;
  constructor(host: string, opts?: MqttConnOpt) {
    this.connect(host, opts);
  }
  /**  订阅主题  */
  public subscribe(topic: string, qos: 0 | 1 | 2) {
    if (this.isConnected()) {
      console.log('订阅主题----', topic, qos);
      this.mqClient.subscribe(topic, { qos })
    }
  }
  /**  是否已连接到服务器 */
  public isConnected() {
    return this.mqClient.connected == true
  }
  connect(host: string, opts?: MqttConnOpt) {
    this.mqClient = mqtt.connect(host, opts);
    this.mqClient.on('connect', () => {
      console.log('连接成功---', this.mqClient.connected)
    })
    this.mqClient.on('message', (topic: string, payload: Buffer) => {
      console.log('数据响应了---', topic);
      Emitter.emit(topic, payload)
    })
    this.mqClient.on('error', (err: Error) => {
      console.log('连接错误--------------------', err)
    })
    this.mqClient.on('reconnect', () => {
      console.log('重连中......')
    })
  }
}

export default {
  install(app: App, connection: string, opts: MqttConnOpt): void {
    // 没有传入连接,抛出异常
    if (!connection) {
      throw new Error("[mqtt] cannot locate connection");
    }
    const mqtt = new MQTT(connection, opts);
    app.config.globalProperties.$mqtt = mqtt;
    const hasProxy = typeof Proxy !== "undefined" && typeof Proxy === "function" && /native code/.test(Proxy.toString());

    app.mixin({
      created() {
        const mqtts = this.$options["mqtts"];
        const vm = this;
        if (hasProxy) {
          this.$options.mqtts = new Proxy(
            {},
            {
              set(target: any, key: any, value: any): boolean {
                // 添加监听
                mqtt.subscribe(key, 0)
                Emitter.addListener(key, value, vm);
                Reflect.set(target, key, value)
                return true;
              },
              deleteProperty(target: { key: any }, key: any): boolean {
                console.log('remove listener--', key)
                // 移除监听
                Emitter.removeListener(key, vm.$options.mqtts[key], vm);
                Reflect.deleteProperty(target, key)
                return true;
              }
            }
          );
          if (mqtts) {
            Object.keys(mqtts).forEach((key: string) => {
              // 给$options中添加mqtts中的key
              this.$options.mqtts[key] = mqtts[key];
            });
          }
        }
      },
      beforeUnmount() {
        if (hasProxy) {
          const mqtts = this.$options["mqtts"];
          if (mqtts) {
            Object.keys(mqtts).forEach((key: string) => {
              // 销毁前如果代理存在mqtts存在则移除$options中给mqtts添加过的key
              delete this.$options.mqtts[key];
            });
          }
        }
      }
    })
  }
}

3.Emitter

utils/mqtt/Emitter.ts

export class Emitter<T = any> {
  private listeners: Map<any, any>;
  constructor() {
    this.listeners = new Map();
  }
  /**
   * 添加事件监听
   * @param label 事件名称
   * @param callback 回调函数
   * @param vm this对象
   * @return {boolean}
   */
  addListener(label: T, callback: (...params: T[]) => void, vm: T): boolean {
    if (typeof callback === "function") {
      // label不存在就添加
      this.listeners.has(label) || this.listeners.set(label, []);
      // 向label添加回调函数
      this.listeners.get(label).push({ callback: callback, vm: vm });
      return true;
    }
    return false;
  }

  /**
   * 移除监听
   * @param label 事件名称
   * @param callback 回调函数
   * @param vm this对象
   * @return {boolean}
   */
  removeListener(label: T, callback: () => void, vm: T): boolean {
    // 从监听列表中获取当前事件
    const listeners = this.listeners.get(label);
    let index;
    if (listeners && listeners.length) {
      // 寻找当前事件在事件监听列表的位置
      index = listeners.reduce((i: number, listener: any, index: number) => {
        if (
          typeof listener.callback === "function" &&
          listener.callback === callback &&
          listener.vm === vm
        ) {
          i = index;
        }
        return i;
      }, -1);

      if (index > -1) {
        // 移除事件
        listeners.splice(index, 1);
        this.listeners.set(label, listeners);
        return true;
      }
    }
    return false;
  }
  /**
   * 触发监听
   * @param label 事件名称
   * @param args 参数
   * @return {boolean}
   */
  emit(label: string, ...args: T[]): boolean {
    // 获取事件列表中存储的事件
    const listeners = this.listeners.get(label);
    if (listeners && listeners.length) {
      listeners.forEach((listener: { callback: (...params: T[]) => void; vm: T }) => {
        // 扩展callback函数,让其拥有listener.vm中的方法
        listener.callback.apply<any, any, any>(listener.vm, [label, ...args]);
      }
      );
      return true;
    }
    return false;
  }
}
export default new Emitter();