【vue3系列实战三(第一节)】vue3 + websocket 多人聊天室实战基础

Hello,宝子们好呀,今天我们来继续我们vue3 实战练习系列,之前我们学习了 什么是websocket基础。今天我们就使用vue3 + websocket + nodejs进行实战开发,【多人聊天室】。

项目预览:内容较多,作者还在持续更新,这个属于大实战了,请大家持续关注。第二节已经更新聊天室实战

一:项目梳理:

我们需要考虑前端交互、实时通信和用户体验等多个方面。

一、技术选型

前端

  • Vue3:核心框架 + Composition API
  • Socket.io-client:实时通信
  • Pinia:状态管理(用户信息/消息存储)
  • UI框架:Element Plus + tailwindcss
  • Day.js:时间格式化

后端

  • Node.js:运行环境
  • Express/Koa:HTTP服务(我就使用koa了,大家可以自行选择熟悉的nodejs框架)
  • Socket.io:WebSocket服务
  • MongoDB:消息持久化(如果对数据库不熟悉,大家可以去熟悉一下api)
  • JWT:身份验证(token)

注意:为什么使用MongoDB? MongoDB 是文档型数据库,使用(JSON 的二进制形式)存储数据,无需预定义模式。对于实时应用(如聊天记录、实时通知),简单来说,适合高频次的数据写入场景。

二、核心功能模块

1. 用户系统

  • 登录/登出
  • 用户信息存储(用户名、头像等)
  • 用户状态管理(在线/离线)

2. 实时通信

  • 消息发送/接收
  • 消息类型支持(文本)(图片和文件后续做大实战可以加入功能)
  • 消息状态反馈(发送中/已送达/已读)

3. 聊天室管理

  • 公共聊天室
  • 私人聊天(可选)

总体思路架构了解清楚了,不过不用着急,我们先来做一个简易的vue3 + nodejs的聊天室!

二:简易的vue3 + nodejs的聊天室:

目录结构:

src
├── App.vue
├── components
│   ├── ConnectionManager.vue
│   ├── ConnectionState.vue
│   └── MyForm.vue
├── main.ts
└── socket.ts

初始化项目 + 安装依赖:
在这里插入图片描述

npm create vite@latest vue3-chat-room-base -- --template vue+ts

安装依赖:
在这里插入图片描述

npm install socket.io-client

Socket.IO 客户端在 src/socket.ts 文件中初始化:

由于要使用到process.env.NODE_ENV,所以需要安装:

npm i --save-dev @types/node

在这里插入图片描述

代码如下:

import { io } from "socket.io-client";
import { reactive } from "vue";

export const state = reactive({
    connected: false, // 是否连接
    fooEvents:[] as Array<any>, // 事件列表
    barEvents:[] as Array<any>  // 事件列表
});
// socket服务器地址
const URL = process.env.NODE_ENV === "production" ? 'yourdomin.com' : "http://localhost:3000"; 

export const socket = io(URL); // 连接socket服务器

socket.on("connect", () => { // 连接成功
    state.connected = true;
});

socket.on("disconnect", () => { // 断开连接
    state.connected = false;
});

socket.on("foo", (...data) => { // 监听foo事件
    state.fooEvents.push(data);
});

socket.on("bar", (...data) => { // 监听bar事件
    state.barEvents.push(data);
});

在src/components/ConnectionState.vue
使用计算属性展示连接状态:
在这里插入图片描述

<template>
    <div>
        <p>链接状态:{{ connected }}</p>
    </div>
</template>

<script setup lang="ts">
import { computed } from 'vue';
import { state } from '../socket';

    const connected = computed(() => {
        return state.connected ? '已连接' : '连接已断开';
    })


</script>

<style scoped>

</style>

在src/components/ConnectionManager.vue,绑定事件:

<template>
    <div>
        <button @click="handleConnection">连接</button>
        <button @click="handleDisconnection">断开连接</button>
    </div>
</template>

<script setup lang="ts">
import { socket } from '../socket';

const handleConnection = () => {
    socket.connect();
}
const handleDisconnection = () => {
    socket.disconnect(); 
}

</script>

<style scoped>

</style>

MyForm.vue:

<template>

    <form>
        <input v-model="value" />
        <button type="submit" :disabled="isLoading">提交</button>
    </form>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const value = ref('');
const isLoading = ref(false);


</script>

<style scoped></style>

App.vue,由于只是练手,我们就不做样式的美化了:

<script setup lang="ts">
  import ConnectionManager from './components/ConnectionManager.vue';
  import ConnectionState from './components/ConnectionState.vue';
  import MyForm from './components/MyForm.vue';
</script>

<template>
  <div>
    <ConnectionState />
    <div style="margin: 20px;">
      <MyForm />

    </div>
    <ConnectionManager />

  </div>
</template>

<style scoped>
</style>

最终页面:
在这里插入图片描述
现在我们来写服务器

之前 websocket专题 我已经进行教学了,大家可以迅速浏览一下,查看用法。

在这里插入图片描述

npm init -y
npm install express socket.io

现在我们来创建服务:
index.js

import express from 'express';
import { createServer } from 'node:http';
import { Server } from 'socket.io';

const app = express();
const server = createServer(app);

  const io = new Server(server,{
    cors: {
      origin: "http://localhost:5173", // 允许的前端域名
      methods: ["GET", "POST"], // 允许的请求方法
      credentials: true // 允许凭据(如 cookies)
    },
    connectionStateRecovery: {} // 开启连接状态恢复

  });

io.on('connection', (socket) => { // 监听连接事件,当有客户端连接时触发
  console.log('已连接!!!'); // 打印连接信息

  socket.on('disconnect', () => { // 监听断开连接事件,当有客户端断开连接时触发
    console.log('连接断开!!!'); // 打印断开连接信息
  })
})

server.listen(3000, () => {
  console.log('server running at http://localhost:3000');
});

关键点在这里:
在这里插入图片描述
必须要配置跨域,才可以访问得到,浏览器的同源策略,需要协议域名端口号都相同才可以访问,我们之前做的例子就是都在localhost:3000访问,所以不需要配置跨域,除了服务端,我们的客户端也需要配置:
在这里插入图片描述

export const socket = io(URL,{
    withCredentials: true, // 跨域
}); // 连接socket服务器

现在我们来查看我们的页面:

node index.js

在这里插入图片描述
如果显示下图,代表连接成功!:
在这里插入图片描述
现在我们来发送消息看看是否能够接收到消息:
我们需要在服务端的connect方法体里面去发布消息,客户端去订阅相同的消息,只要订阅消息的用户都可以接收到消息

现在先在服务端添加事件监听:
在这里插入图片描述

 socket.on('message', (msg,callback) => { // 监听 message 事件,当有客户端发送消息时触发
    io.emit('foo', msg +'已收到!!!');// 将消息广播给所有客户端,
    callback({
      code: 200,
      data: '已收到!!!'
    })
  })

现在我来解释一下这段代码:大白话解释: socket.on(‘message’)的意思是订阅message的事件,如果你发布的message事件,那我就可以接收到,是不是非常简单。 io.emit(‘foo’, msg +‘已收到!!!’); 这句话可以理解为,当我接收到消息后,我也发布了一个foo事件,如果你订阅了foo事件,那你就能得到我发送给你的消息。
至于这个callback的作用是,客户端的回调:
在这里插入图片描述
代码入下:

<template>
    <div>
        {{ state.fooEvents }}
    </div>
    <form @submit.prevent="onSubmit">
        <input v-model="value" />
        <button type="submit" :disabled="isLoading">提交</button>
    </form>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { socket, state } from '../socket';

const value = ref('');
const isLoading = ref(false);

const onSubmit = () => {
    isLoading.value = true;
    socket.emit('message', value.value, (response: string) => {
        console.log('response', response); // 处理服务器的响应
        isLoading.value = false;
    })
}
</script>

<style scoped></style>

现在重启服务:
在这里插入图片描述

如果大家也能得到这个结果,代表你也成功了!
小结:我们通过vue3 + socket.io实现了一个简易的聊天室,大家可以根据自己的需求进行拓展!后续我将带来大实战:【vue3系列实战三(下)】vue3 + websocket 多人聊天室实战,敬请期待!大家多多关注呀!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值