| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- <!-- MqttComp.vue -->
- <template>
- <div class="mqtt-comp" style="display: none"></div>
- </template>
- <script>
- import mqtt from "mqtt/dist/mqtt.min.js";
- export default {
- name: "MqttComp",
- props: {
- mqttUrl: {
- type: Object,
- default: () => ({
- head: "ws", // ws 或 wss
- host: "8.148.78.124",
- port: 8083,
- path: "/mqtt",
- }),
- },
- mqttOpts: {
- type: Object,
- default: () => ({
- keepalive: 60,
- clientId: "clientId-" + Math.random().toString(16).substr(2, 8),
- username: "",
- password: "",
- clean: true,
- connectTimeout: 10 * 1000,
- reconnectPeriod: 2000,
- }),
- },
- topics: {
- type: Array,
- default: () => [], // 可一次性传入多个 topic
- },
- },
- data() {
- return {
- client: null,
- isConnected: false,
- subscribedTopics: [], // 内部管理的已订阅 topic
- };
- },
- watch: {
- topics: {
- handler(newTopics) {
- if (!this.client || !this.isConnected) return;
- // 取消订阅已经移除的 topic
- this.subscribedTopics.forEach((t) => {
- if (!newTopics.includes(t)) {
- this.unsubscribeTopic(t);
- }
- });
- // 订阅新增 topic
- newTopics.forEach((t) => {
- if (!this.subscribedTopics.includes(t)) {
- this.subscribeTopic(t);
- }
- });
- },
- deep: true,
- immediate: true,
- },
- },
- methods: {
- // 初始化 MQTT 连接
- initMqtt() {
- const { head, host, port, path } = this.mqttUrl;
- const connectUrl = `${head}://${host}:${port}${path || ""}`;
- console.log("MQTT连接地址:", connectUrl);
- this.client = mqtt.connect(connectUrl, this.mqttOpts);
- this.client.on("connect", () => {
- this.isConnected = true;
- console.log("✅ MQTT 已连接");
- this.$emit("mqtt-connected");
- // 自动订阅传入的 topic
- this.topics.forEach((topic) => this.subscribeTopic(topic));
- });
- this.client.on("message", (topic, message) => {
- let msg;
- try {
- msg = JSON.parse(message.toString());
- } catch {
- msg = message.toString();
- }
- this.$emit("message-received", { topic, message: msg });
- });
- this.client.on("reconnect", () => {
- console.log("♻️ MQTT 正在重连...");
- this.$emit("mqtt-reconnect");
- });
- this.client.on("error", (err) => {
- console.error("❌ MQTT连接失败:", err);
- this.$emit("mqtt-error", err);
- });
- this.client.on("close", () => {
- this.isConnected = false;
- console.log("🔌 MQTT连接已关闭");
- this.$emit("mqtt-close");
- });
- },
- // 订阅单个 topic
- subscribeTopic(topic) {
- if (!this.client || !this.isConnected) {
- console.warn("MQTT 未连接,无法订阅:", topic);
- return;
- }
- if (!topic || this.subscribedTopics.includes(topic)) return;
- this.client.subscribe(topic, (err) => {
- if (!err) {
- console.log("订阅成功:", topic);
- this.subscribedTopics.push(topic);
- this.$emit("topic-subscribed", topic);
- }
- });
- },
- // 取消订阅单个 topic
- unsubscribeTopic(topic) {
- if (!this.client || !this.isConnected) return;
- if (!topic || !this.subscribedTopics.includes(topic)) return;
- this.client.unsubscribe(topic, (err) => {
- if (!err) {
- console.log("取消订阅:", topic);
- this.subscribedTopics = this.subscribedTopics.filter((t) => t !== topic);
- this.$emit("topic-unsubscribed", topic);
- }
- });
- },
- // 发布消息
- publish(topic, message) {
- if (!this.client || !this.isConnected) {
- console.warn("MQTT 未连接,消息未发送:", topic);
- return;
- }
- console.log("sdfdsf",typeof message === "object");
-
- const payload = typeof message === "object" ? JSON.stringify(message) : String(message);
- this.client.publish(topic, payload);
- },
- // 断开连接,取消所有订阅
- disconnect() {
- if (this.client) {
- // 先取消所有订阅
- this.subscribedTopics.forEach((t) => this.unsubscribeTopic(t));
- this.client.end(true, () => {
- console.log("🔌 MQTT手动断开成功");
- });
- }
- },
- },
- mounted() {
- this.initMqtt();
- },
- beforeDestroy() {
- this.disconnect();
- },
- };
- </script>
- <style scoped>
- .mqtt-comp {
- display: none;
- }
- </style>
|