iT邦幫忙

2021 iThome 鐵人賽

DAY 23
0
Modern Web

摸索 WebSocket,遠望 WebRTC系列 第 23

Day22:ws 整合 Vue 渲染聊天訊息

前面的 socket.io 使用原生 JS 來寫 Demo,這邊就試著改用框架來處理,不過畢竟目前還是 Demo 練習性質,所以就直接用 CDN 引入,不使用 cli,至於版本的部分,暫時先用 2.6 版。

Template

先用 script 引入 cdn,再使用 app 去包,每一則訊息的渲染則是透過 v-for 放在 li 標籤上,省了 innerHTML 的書寫。

input 透過 v-model 雙向綁定輸入的值,button 不用透過 DOM 操作,可以直接使用 click 事件來觸發 function。

client / index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
  </head>
  <body>
    <div id="app">
      <input type="text" class="input-message" v-model="message" />
      <button type="button" class="send-btn" @click="sendMessage()">
        Send Message
      </button>
      <ul class="message-wrapper">
        <li v-for="(item, index) in list" :key="index + item">{{ item }}</li>
      </ul>
    </div>

    <script src="./client.js"></script>
  </body>
</html>

Client

把原本的 DOM 操作通通拔掉,也不需要額外寫 addEventListener()

list 是用來存放訊息的陣列,所以當使用者送出輸入的訊息時,列表即會更新變化,在 sendMessage() 觸發,但對其他使用來說,他必須等到 server-side 轉發訊息回來,再透過 onMessage() 監聽的方式,觸發列表變化,這是流程上兩者的差異。

client / client.js

const app = new Vue({
  el: '#app',
  data: {
    list: [],
    message: '',
    ws: {},
  },

  mounted() {
    this.ws = new WebSocket('ws://127.0.0.1:3000');
    this.ws.onopen = this.onOpen;
    this.ws.onmessage = this.onMessage;
    this.ws.onclose = this.onClose;
    this.ws.onerror = this.onError;
  },

  methods: {
    onOpen() {
      console.log(`open : ${this.ws.readyState}`);
    },
    onMessage(event) {
      this.list.push(event.data);
    },
    onClose() {
      console.log(`close : ${this.ws.readyState}`);
    },
    onError() {
      console.log(`error : ${this.ws.readyState}`);
    },
    sendMessage() {
      this.list.push(this.message);
      this.ws.send(this.message);
      this.message = '';
    },
  },
});

Server

server-side 在轉發訊息時,需要先確認兩件事,因為廣播事件是傳遞給目前線上的所有使用者,所以第一個需要先過濾掉訊息發送者。舉例來說:

A, B 兩個玩家同時登入在線上,A 玩家送出訊息 Hello all!,自然系統不需要對 A 玩家發出這則訊息,僅需要通知 B 玩家,反之,B 玩家送出訊息時也是同理。

第二個則是確認該玩家是否斷線,所以透過 readyState 的值來檢查是否符合 WebSocket 保持連線的值,確認目前的玩家列表中,那些人仍維持上線狀態,並只針對這些人發送訊息。

server / server.js

const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 3000 });

wss.on('connection', function connection(ws) {
  ws.on('message', function (message) {
    const bufferMessage = Buffer.from(message).toString();
    wss.clients.forEach((client) => {
      if (ws !== client && client.readyState === WebSocket.OPEN) {
        client.send(bufferMessage);
      }
    });
  });
});


上一篇
Day21:使用 ws 實作訊息傳遞
下一篇
Day23:進入聊天室狀態判斷
系列文
摸索 WebSocket,遠望 WebRTC30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言