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/[email protected]"></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);
      }
    });
  });
});


<<:  D24 - 「不断线的侏罗纪」:天上好多云、地上一堆仙人掌

>>:  [ Day 23 ] Redux 中的核心概念

增加 App 下载量必备的 ASO 工具

场景与需求 APP跟网页一样,要被下载,最容易的办法就是要取得流量大的关键字的上位排名,也就是要做S...

【Day12】数据展示元件 - Tooltip

元件介绍 Tooltip 是一个文字弹出提醒元件,当 active 状态时,会显示对该子元件描述的文...

Day 26:Google Map 范本学习(1)

本篇文章同步发表在 HKT 线上教室 部落格,线上影音教学课程已上架至 Udemy 和 Youtu...

D8: 工程师太师了: 第4.5话

工程师太师了: 第4.5话 杂记: 索引 (index) 索引是用以识别阵列各元素的符号,阵列中每个...

【演算法】L1 演算法评估

演算法评估 ### 演算法衡量 效率 渐进符号 EX:O(n) 最差案例 平均案例 平摊分析 问题衡...