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 多人聊天室实战,敬请期待!大家多多关注呀!