前言

在vue前端项目中全局使用websocket,需要用到全局状态管理(这里使用vuex),为方便以后类似场景搭建,这里记录一下。

具体步骤

  1. 封装websocket类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    // @/utils/websocket.js 
    export default class WebSocketClient {
    constructor(url, onMessageCallback, onErrorCallback) {
    this.token = localStorage.getItem("lidar_token");
    let socketUrl = `ws://your-base-url`;
    this.url = socketUrl + url;

    this.onMessageCallback = onMessageCallback;
    this.onErrorCallback = onErrorCallback || (() => {});
    this.ws = null;
    this.reconnectDelay = 5000; // 重连间隔
    }

    connect() {
    this.ws = new WebSocket(this.url, [this.token]);
    this.ws.onopen = () => {
    console.log("socket连接成功");
    };

    this.ws.onmessage = (event) => {
    const raw = event.data;
    const data = JSON.parse(raw);
    if (this.onMessageCallback) {
    this.onMessageCallback(data);
    // this.onMessageCallback(event.data);
    }
    };

    this.ws.onerror = (error) => {
    console.error("连接失败:", error);
    this.onErrorCallback(error);
    };

    this.ws.onclose = () => {
    console.log("连接已断开.");
    // 可以加一个字段,是否需要重连
    // console.log("连接已断开,尝试重连...");
    // setTimeout(() => this.connect(), this.reconnectDelay);
    };
    }

    sendMessage(message) {
    if (this.ws && this.ws.readyState === WebSocket.OPEN) {
    this.ws.send(message);
    } else {
    console.error("WebSocket is not open.");
    }
    }

    close() {
    if (this.ws) {
    this.ws.close();
    }
    }
    }
  2. 配置状态管理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    // @/store/modules/websocket.js 管理状态
    import WebSocketClient from "@/utils/websocket";

    const state = {
    websocket: null,
    isConnected: false,
    messages: null,
    };

    const mutations = {
    SET_WEBSOCKET(state, websocket) {
    state.websocket = websocket;
    },
    SET_CONNECTION_STATUS(state, status) {
    state.isConnected = status;
    },
    ADD_MESSAGE(state, message) {
    state.messages= message;
    },
    CLEAR_MESSAGES(state) {
    state.messages= null;
    },
    };

    const actions = {
    initializeWebSocket({ commit, dispatch }, url) {
    const websocket = new WebSocketClient(
    url,
    (message) => {
    dispatch("handleMessage", message);
    },
    (error) => {
    console.error("WebSocket error from vuex:", error);
    },
    true
    );
    websocket.connect();
    commit("SET_WEBSOCKET", websocket);
    commit("SET_CONNECTION_STATUS", true);
    },
    closeWebSocket({ commit, state }) {
    if (state.websocket) {
    state.websocket.close();
    commit("SET_CONNECTION_STATUS", false);
    }
    },
    sendMessage({ state }, message) {
    if (state.websocket) {
    state.websocket.sendMessage(message);
    } else {
    console.error("WebSocket is not connected.");
    }
    },
    // TODO:这里可以进行消息分类的处理
    handleMessage({ commit }, message) {
    commit("ADD_MESSAGE", message);
    },
    };

    const getters = {
    isConnected: (state) => state.isConnected,
    messages: (state) => state.messages,
    };

    export default {
    namespaced: true,
    state,
    mutations,
    actions,
    getters,
    };
  3. 全局派发

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // main.js
    new Vue({
    router,
    store,
    render: (h) => h(App),
    created() {
    const websocketUrl = "/your-url";
    this.$store.dispatch("websocket/initializeWebSocket", websocketUrl);
    },
    beforeDestroy() {
    this.$store.dispatch("websocket/closeWebSocket");
    },
    }).$mount("#app");
  4. 组件中使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 在组件中获取/监听状态
    import { mapGetters } from "vuex";

    computed: {
    ...mapGetters("websocket", ["messages", "isConnected"]),
    },
    watch: {
    messages: {
    handler(newMessages) {
    if (newMessages) {
    // your function
    }
    },
    deep: true,
    },
    },
  5. more: 单个页面使用websocket

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // 组件使用: 组件内声明一个socketServiceData状态; beforeDestroy钩子记得.close()
    if (this.socketServiceData) {
    this.socketServiceData.close();
    this.socketServiceData = null;
    }
    this.socketServiceData = new WebSocketClient(
    "/your-url",
    (message) => {
    // your function
    },
    (error) => {
    // your function
    }
    );
    this.socketServiceData.connect();

done!