WebSocket 实现在线聊天室

准备工作

  • 前端部分就直接跳过了
  • 只需要一个输入框和聊天区域
// git 初始化
git init
// 安装 ws
npm i ws

实现逻辑

  • 当用户进入聊天室,分配用户 Id、用户头像;(后续扩展:后续可以通过 token 获取用户信息,因为是模拟的所以随机分配信息)

  • 用户信息与其关联的客户端 webSocket 链接

  • 存储用户信息之后,将用户信息发送给前端

  • 同时发送当前聊天室的用户列表,给所以已经连接的用户

  • 用户下线时,从用户列表中剔除下线用户,并通知所有在线用户

  • 用户格式:

interface User {
  id: string;
  name: string;
  avatar: string;
}
  • 用户发送信息格式:
interface Info {
  id: string;
  name: string;
  avatar: string;
  time: string;
  message: string;
}

消息类型:

  • user: 表示发送用户登录时给到的用户信息
  • message:表示发送的消息
  • userList:表示所有的用户列表
interface type {
  type: "user" | "message" | "userList";
}

引入 socket 设置 3000 端口

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

定义一个用户组用来放用户,声明下一个用户 id

const user = []; // 用户组
let nextUserId = 1; // 下一个id

使用 connection 连接

wss.on("connection", (ws) => {});

send 用于发送数据 ws.send()

监听客户端的 message 消息

ws.on("message", (data) => {});

监听用户关闭连接

ws.on("close", () => {});

前端配置

在初始化后监听

// 收到的消息
ws.addEventListener("message", ({ data }) => {
  const res = JSON.parse(data); // 收到服务端发来的message
});

截图

01.png

02.png

03.png

server.js 完整代码

// server.js
const WebSocket = require("ws");
const wss = new WebSocket.Server({ port: 3000 });

const user = []; // 用户组
let nextUserId = 1; // 下一个id
const sendAll = (message) => {
  // 给每个用户发送一下消息
  user.forEach((item) => item.ws.send(JSON.stringify(message)));
};
wss.on("connection", (ws) => {
  // 每次进来一个用户,就把下一个id赋值给它
  const userId = nextUserId;
  const userInfo = {
    id: userId,
    name: (userId % 2 !== 0 ? "汤姆" : "杰克") + userId,
    avatar: `avatar/0${(userId % 2) + 1}.png`,
    ws,
  };

  console.log(userId, "进来了");
  nextUserId += 1; // 自增id
  user.push(userInfo); // 将新的用户保存到用户组中

  // 发送最新进来的人,在线人数
  sendAll({
    type: "userList",
    userId,
    userCount: user.length,
    userList: user.map((item) => {
      const { ws, ...data } = item;
      return data;
    }),
  });

  // 给自己发送一个消息,告知客户端身份
  ws.send(
    JSON.stringify({
      type: "user",
      userInfo: {
        id: userInfo.id,
        name: userInfo.name,
        avatar: userInfo.avatar,
      },
    })
  );

  // 接收来自客户端的消息
  ws.on("message", (data) => {
    const res = {
      id: userId,
      type: "message",
      data: JSON.parse(data),
    };
    // 设置一个给所有用户发送一下最最新消息
    sendAll(res);
  });

  ws.on("close", () => {
    console.log(userId, "离开了");
    // 用户离开了,需要删除属于他的聊天内容
    user.splice(
      user.findIndex((item) => item.id === userId),
      1
    );
    // 有人离开,发送用户列表通知
    sendAll({
      type: "userList",
      userId,
      userCount: user.length,
      userList: user.map((item) => {
        const { ws, ...data } = item;
        return data;
      }),
    });
  });
});

前端操作内容

import { ref } from "vue";
import { message } from "ant-design-vue";
const [messageApi] = message.useMessage();

interface User {
  id: string;
  name: string;
  avatar: string;
}
interface Info {
  id: string;
  name: string;
  avatar: string;
  time: string;
  message: string;
}

// 聊天信息
const info = ref<Info[]>([]);
// 当前用户
const user = ref<User>({
  id: "",
  name: "",
  avatar: "",
});
// 在线人数
const people = ref<User[]>([]);

const numPeople = ref<number>(0);
const input = ref<string>("");

// 点击发送
const onClickInput = () => {
  if (input.value !== "") {
    const data = {
      ...user.value,
      message: input.value,
    };
    // send 发送,需要把json转为字符串
    ws.send(JSON.stringify(data));
    input.value = "";
  }
};

const ws = new WebSocket("ws://localhost:3000");
ws.addEventListener("open", () => {
  console.log("连接上服务器");
  // send 发送数据
  // ws.send('来新订单了!')
});

// 收到的消息
ws.addEventListener("message", ({ data }) => {
  const res = JSON.parse(data);
  // console.log('res:',res.data)
  // 用户列表
  if (res.type === "userList") {
    numPeople.value = res.userCount;
    people.value = res.userList;
    console.log("当前在线人数" + numPeople.value);
    messageApi.info("当前在线人数" + numPeople.value);
  }
  // 新增消息
  if (res.type === "message") {
    info.value.push(res.data);
  }
  // 用户个人信息
  if (res.type === "user") {
    user.value = res.userInfo;
  }
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值