越寫悅快樂之Vue項目如何集成WebSocket

作爲一名有追求的碼農來說,不管是前端、後端、抑或是測試、運維,都需要保持一定的好奇心纔可以,那麼大家都知道Vue作爲前端框架的集大成者,擁有着易用、靈活和高效的優點,那麼對於在Vue項目中集成WebSocket,大家有沒有實踐過呢?今天我爲大家分享一下如何在Vue項目中集成WebSocket。

開發環境

  • Window 10.0.17763
  • Node 10.18.0
  • Visual Studio Code 1.48.2
  • Vue 2.6.12

特別說明

本項目使用SockJS-ClientSTOMP.js來支持WebSocket後端(Node.js、Java等),在支持WebSocket的瀏覽器中可以直接進行連接、消息收發和端口等操作(詳細內容請參考相關文檔)。

接入步驟

添加依賴

我們在項目的入庫頁面(index.html)中通過CDN的方式引入SockJS-ClientSTOMP.js,文件內容如下。

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="renderer" content="webkit" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
    />
    <title>信息管理系統</title>
  </head>
  <body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.5.0/sockjs.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
    <div id="app"></div>
  </body>
</html>

在Vue文件中連接和關閉WebSocket

既然我們在項目的入口頁面中引入了WebSocket相關庫,那麼掛載在app下的Vue組件均可以使用STOMPSockJS,此時我們在Vue的生命週期函數mounted、和beforeDestroy中分別調用WebSocket的初始化和銷燬函數,在data中聲明WebSocket連接的HostTopic等相關變量,下面給出Vue文件的內容如下。

<template>
<div class="app-container">
    <el-row>
        <el-col>
            <search @getTableData="getTableData" @deleteSelected="remove"></search>
        </el-col>
    </el-row>
    <el-row>
        <el-col>
            <Table @search="search" :data="gridData" :table="table" :pageParams="pageParams" :pageSizes="[10, 20, 50]" @getSelected="getSelected"></Table>
        </el-col>
        <el-button @click="sendMessage">發送消息</el-button>
    </el-row>
</div>
</template>

<script>
import {
    list,
    save
} from "@/api/dashboard/enterprise/myMessage";

import Table from "@/components/table";

import to from "@/to";

import {
    getToken
} from "@/utils/auth";

import search from "./search";

import {
    mapState,
    mapActions
} from "vuex";

const moment = require("moment");

export default {
    name: "MesageList",
    components: {
        Table,
        search
    },
    data: function () {
        return {
            table: {
                // 行定義
                columns: [{
                        prop: "content",
                        label: "消息內容",
                        width: ""
                    },
                    {
                        prop: "sender",
                        label: "發送者",
                        width: ""
                    },
                    {
                        prop: "typeName",
                        label: "消息類型",
                        width: ""
                    }
                ],
                total: 0
            },
            wsHost: "http://localhost:8080/websocket",
            wsTopic: "/topic/greeting",
            websocket: null,
            stompClient: null,
            isConnected: false,
            message: {},
            messages: [],
            headers: {
                Authorization: getToken()
            }
        };
    },
    computed: {
        ...mapState("dashboard/message/index", [
            "editDialogVisible",
            "editDialogTitle",
            "gridData",
            "pageParams",
            "checkboxSelected",
            "params",
            "total",
            "form"
        ])
    },
    mounted() {
        this._initSockJs();
    },
    beforeDestroy() {
        this._destroySockJs();
    },
    methods: {
        ...mapActions("dashboard/message/index", ["setStateData"]),
        // 操作回調
        action(obj) {
            if (obj.methods === "delete") {
                this.setStateData({
                    checkboxSelected: [obj.row]
                });
                this.remove();
            }
        },
        // 刪除
        remove() {
            if (this.checkboxSelected && this.checkboxSelected.length > 0) {
                this.$confirm("此操作將永久刪除, 是否繼續?", "提示", {
                        confirmButtonText: "確定",
                        cancelButtonText: "取消",
                        type: "warning"
                    })
                    .then(async () => {
                        let [err, res] = await to(deleteByIds(this.checkboxSelected));
                        if (err) {
                            throw new Error(err.message);
                        }
                        this.$message({
                            type: "success",
                            message: "刪除成功"
                        });
                        this.getTableData();
                    })
                    .catch(() => {
                        this.$message({
                            type: "info",
                            message: "已取消刪除"
                        });
                    });
            }
        },
        // 查詢
        search(pageParams) {
            this.setStateData({
                pageParams: pageParams
            });
            this.getTableData();
        },
        // 選中回調
        getSelected(multipleSelection) {
            this.setStateData({
                checkboxSelected: multipleSelection
            });
        },
        // 獲取數據
        async getTableData() {
            let response = await list(this.params, this.pageParams);
            let gridData = response.data.list;
            let total = response.data.total;
            this.setStateData({
                gridData: gridData
            });
            this.table.total = total;
        },
        _initSockJs() {
            this.getTableData();
            this.socket = new SockJS(this.wsHost);
            this.stompClient = Stomp.over(this.socket);
            // 訂閱
            this.stompClient.connect(this.headers, frame => {
                console.log("WebSocket連接成功", frame);
                this.isConnected = true;
                // 廣播
                this.stompClient.subscribe(this.wsTopic, response => {
                    console.log("/websocket/message", JSON.parse(response.body));
                    this.messages.push(JSON.parse(response.body));
                    this.setStateData({
                        gridData: this.messages
                    });
                });
                // 一對一
                this.stompClient.subscribe("/user/topic/greeting", response => {
                    console.log(
                        "/user/topic/greeting/message",
                        JSON.parse(response.body)
                    );
                    this.messages.push(JSON.parse(response.body));
                    this.setStateData({
                        gridData: this.messages
                    });
                });
                // 廣播
                this.stompClient.subscribe("/topic/greeting", response => {
                    console.log("/topic/greeting/message", JSON.parse(response.body));
                    this.messages.push(JSON.parse(response.body));
                    this.setStateData({
                        gridData: this.messages
                    });
                });
            });
        },
        _destroySockJs() {
            if (this.stompClient != null) {
                this.stompClient.disconnect();
                this.socket.onclose;
                this.socket.close();
                this.stompClient = {};
                this.socket = {};
                this.isConnected = false;
            }
            console.log("WebSocket斷開成功");
        },
        async sendMessage() {
            this.message = {
                sender: this.$store.getters.introduction,
                type: "3",
                content: "消息內容",
                receiver: "*",
                sendingDate: moment(new Date()).format("YYYY-MM-DD HH:mm:ss")
            };

            let [err, res] = await to(save(this.message));
            if (err) {
                throw new Error(err.message);
            }

            this.stompClient.send(this.wsTopic, {}, JSON.stringify(this.message));

            this.$message({
                showClose: true,
                message: "消息發送成功",
                type: "success"
            });
        }
    }
};
</script>

sendMessage函數用於測試消息發送,發送完消息後持久化消息並通過訂閱的Topic即時收取消息,收到消息後保存到表格中。

getToken函數是爲了獲取登錄認證後保存的個人信息。

驗證連接結果

我們啓動前後端的項目,然後定位到該頁面,打開開發者工具並切換到控制檯,控制檯會顯示以下信息。

通過以上的截圖我們可以得知WebSocket連接的後端地址,心跳檢測的輸出和stompClient的認證字段,那麼急於此我們可以構建不同的應用場景,比如聊天、消息收發、任務提醒等功能,再配合其他功能來滿足客戶的訴求,我相信WebSocket的接入會讓你的應用更好用。

個人收穫及感想

我們的文章今天爲大家介紹了Vue項目中接入WebSocket的方法,通過連接、收發消息和斷開等方法來接入WebSocket後端,接入之後就可以愉快地集成其他的業務啦。而在現在的複雜多變的產品迭代週期中,WebSocket不可或缺,並且會不斷髮展和變化,相信過不了多久,我們的產品也會慢慢完善,並趨於完美。讓我們一起持續打造能滿足客戶訴求的好產品,持續爲客戶做好服務,成爲更好的團隊和更好的自己。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章