Vue3 無所不能!我用 Vue3 寫接口給前端用你們信嗎?
最近接到一個需求,有兩個頁面分別連接了兩個Websocket連接,并且這兩個頁面可以通過Websocket去相互影響
圖片
為了方便講解,以下會簡化業(yè)務(wù)。
這兩個頁面簡化后如下:
圖片
- 當(dāng)點擊頁面1更新按鈕后,頁面1會+1,而 頁面2 會變成 頁面1 數(shù)值的10倍。
- 當(dāng)點擊頁面2清空按鈕后,頁面1和2的數(shù)值都會變成0。
- 頁面2需要定時去獲取數(shù)值,并展示出來。
效果如下:
圖片
最普通的做法?
其實不難,只需要用 Nodejs新建兩個 Websocket連接,然后維護一個 count變量即可。
npm i ws
至于怎么跨兩個Websocket進行通信呢?其實也簡單,無非就是定義兩個全局變了,去存儲兩個Websocket實例唄!
圖片
接著就是前端頁面進行Websocket通信,即可完成。
Page1
圖片
Page2
圖片
即可完成效果。
圖片
不太好維護吧?
其實這個需求唯一的難點就在于怎么去跨兩個Websocket進行通信,上面的做法是定義兩個全局變量去存儲
但是感覺這樣不太妥,如果以后Websocket連接實例多了,那么維護起來會不會很費勁?
我有個想法:能不能讓每一個 Websocket 連接各自管自己的事
但是其實想要做到各管各的,是有難處的,難就難在于:他們都依賴于count的變化,一個實例改變了 count之后,怎么通知另一個實例去做操作呢?
想到這里我就想到了 Vue3,當(dāng)數(shù)據(jù)變化時,可以監(jiān)聽數(shù)據(jù)變化,并在監(jiān)聽函數(shù)中去做你想做的事情
圖片
那么能不能把Vue3的那一套響應(yīng)式 API 拿到 Nodejs中去用呢?
答案是:可以?。?!Vue3是真的牛,他把 API 都拆出來放在 @vue/reactivity這個包中了,就算你不在瀏覽器環(huán)境,也能用這個包去做響應(yīng)式邏輯,這個包擁有了幾乎所有 Vue 的響應(yīng)式 API。
npm i @vue/reactivity
我們只需要用到ref、computed、watch,即可讓每個 Websocket 實例各管各的。
圖片
圖片
其實大家可以把@vue/reactivity當(dāng)做一個工具庫來看,不要綁定上 Vue,他就是一個響應(yīng)式工具庫!?。∩踔猎?React 項目中也可以用。
// Nodejs 端 index.js
// 引入 WebSocket 庫
const WebSocket = require('ws');
// 引入 Vue 響應(yīng)式 API
const reactivity = require('@vue/reactivity')
const {
ref,
computed,
watch
} = reactivity
// 創(chuàng)建 WebSocket 服務(wù)器
const wss1 = new WebSocket.Server({
port: 8001
});
const wss2 = new WebSocket.Server({
port: 8002
});
// 記錄數(shù)字
const count = ref(0)
// 計算出 10 倍
const sum = computed(() => 10 * count.value)
// 連接1
wss1.on('connection', (ws) => {
// 處理來自客戶端的消息
ws.on('message', (message) => {
// count 變化
count.value = Number(String(message))
});
// 監(jiān)聽 count,并通知頁面2
watch(count, v => {
ws.send(v)
})
});
// 連接2
wss2.on('connection', (ws) => {
// 處理來自客戶端的消息
ws.on('message', () => {
// 執(zhí)行清空命令
count.value = 0
});
// 監(jiān)聽 sum,并通知頁面2
watch(sum, v => {
ws.send(v)
})
// 模擬定時任務(wù)
setTimeout(() => {
ws.send(sum.value)
}, 3600 * 12);
});
<!-- Page1.vue -->
<template>
<div class="flex justify-center mb-3 text-4xl font-bold">頁面1</div>
<Button type="primary" @click="click">點擊更新數(shù)據(jù)</Button>
<div class="text-lg">當(dāng)前數(shù)值:{{ count }}</div>
</template>
<script setup lang="ts">
import { Button } from 'ant-design-vue';
import { ref } from 'vue';
const count = ref(0);
// 創(chuàng)建 WebSocket 客戶端
const socket = new WebSocket('ws://localhost:8001');
const click = () => {
count.value++;
// 發(fā)送消息到服務(wù)器
socket.send(`${count.value}`);
};
// 接受服務(wù)端的消息
socket.addEventListener('message', e => {
count.value = e.data;
});
</script>
<!-- Page2.vue -->
<template>
<div class="flex justify-center mb-3 text-4xl font-bold">頁面2</div>
<Button type="primary" @click="click">清空數(shù)據(jù)</Button>
<div class="text-lg">當(dāng)前數(shù)值:{{ count }}</div>
</template>
<script setup lang="ts">
import { Button } from 'ant-design-vue';
import { ref } from 'vue';
const count = ref(0);
// 創(chuàng)建 WebSocket 客戶端
const socket = new WebSocket('ws://localhost:8002');
const click = () => {
// 發(fā)送消息到服務(wù)器
socket.send('Hello, server!');
};
// 接受服務(wù)端的消息
socket.addEventListener('message', e => {
count.value = e.data;
});
</script>