下面我将详细讲解“vue+socket.io+express+mongodb 实现简易多房间在线群聊示例”的完整攻略,具体步骤如下:
1. 环境准备
在开始编程之前,需要先准备好必要的环境,包括:
- Node.js及npm包管理器
- MongoDB数据库
- Vue.js框架
在确认这些工具已经就绪后,接下来可以开始进行实现了。
2. 服务端实现
本示例中,我们选用了Express作为服务端框架,并集成了Socket.IO作为实现群聊的核心库。
具体实现步骤如下:
2.1. 安装依赖包
首先需要安装相关的依赖包,使用以下命令完成:
npm install --save express socket.io mongodb
2.2. 配置MongoDB数据库
我们需要定义一个数据库模型,来维护用户、房间、聊天记录等相关信息。下面是一个简单的数据模型定义,存储在./models/chat.js中:
const mongoose = require('mongoose');
const ChatSchema = new mongoose.Schema({
messages: [{
from: {type: String},
room: {type: String},
message: {type: String},
createdAt: {type: Date, default: Date.now}
}],
rooms: [String],
users: [String]
}, {
timestamps: true
});
module.exports = mongoose.model('Chat', ChatSchema);
2.3. 实现服务端代码
以下示例代码实现了服务器端的代码,主要包括:
- 创建HTTP服务
- 配置socket.io的事件监听
- 实现连接、断开连接、发送消息等相关事件监听
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const mongoose = require('mongoose');
const ChatModel = require('./models/chat');
const io = require('socket.io')(server);
let port = 3000;
let host = '127.0.0.1';
let clients = {};
let rooms = [];
mongoose.connect('mongodb://localhost:27017/chatroom', { useNewUrlParser: true, useCreateIndex: true });
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB连接错误:'));
db.once('open', () => console.log('MongoDB连接成功!'));
io.on('connection', client => {
console.log(`[SERVER] ${client.id}已连接`);
function joinRoom(room) {
if (rooms.indexOf(room) === -1) {
rooms.push(room);
}
client.join(room);
clients[client.id].room = room;
// 发送房间信息给客户端
io.to(clients[client.id].room).emit('room update', rooms);
console.log(`[SERVER] ${client.id}进入房间 ${room}`);
}
function leaveRoom() {
let room = clients[client.id].room;
client.leave(room);
console.log(`[SERVER] ${client.id}离开房间 ${room}`);
// 删除空房间
if (io.sockets.adapter.rooms[room] === undefined) {
let index = rooms.indexOf(room);
rooms.splice(index, 1);
}
// 发送房间信息给客户端
io.emit('room update', rooms);
}
client.on('join room', data => {
if (!clients[client.id]) {
clients[client.id] = {
name: data.name,
room: null
};
}
joinRoom(data.room);
client.emit('user update', {id: client.id, message: '已加入房间。'});
client.emit('room joined', data.room);
client.to(clients[client.id].room).emit('user update', {id: client.id, message: '已进入房间。'});
});
client.on('leave room', () => {
if (!clients[client.id]) {
return;
}
leaveRoom();
client.emit('user update', {id: client.id, message: '已离开房间。'});
client.to(clients[client.id].room).emit('user update', {id: client.id, message: '已离开房间。'});
});
client.on('disconnect', () => {
console.log(`[SERVER] ${client.id}已断开连接`);
if (clients[client.id]) {
leaveRoom();
delete clients[client.id];
}
io.emit('user update', {id: client.id, message: '已离线。'});
});
client.on('message', message => {
if (clients[client.id]) {
let data = {
from: clients[client.id].name,
room: clients[client.id].room,
message: message
};
// 保存消息记录
ChatModel.update({}, { $push: { messages: data } }, { upsert: true }, (err) => {
if (err) {
console.log(`[SERVER ERROR] ${err}`);
}
});
io.to(clients[client.id].room).emit('message', data);
}
});
});
// 启动HTTP服务
server.listen(port, host, () => {
console.log(`[SERVER] HTTP服务已启动,监听地址为 http://${host}:${port}`);
});
3.客户端实现
我们选用了Vue.js作为客户端框架,使用socket.io-client作为实现群聊的核心库。以下是实现步骤:
3.1. 安装依赖包
首先需要安装相关的依赖包,使用以下命令完成:
npm install --save socket.io-client
3.2. 实现客户端代码
以下示例代码实现了客户端的代码,主要包括:
- 实现连接、断开连接、发送消息等相关事件监听
- Vue模板中嵌入socket.io相关事件监听代码
<template>
<div id="app">
<header>
<h1>在线聊天</h1>
</header>
<div class="chat-body">
<div class="chat-room">
<h5>房间列表({{ rooms.length }})</h5>
<ul>
<li v-for="(room, index) in rooms" :key="index" :class="{ active: room === currentRoom }">
<a @click.prevent="joinRoom(room)">{{ room }}</a>
</li>
</ul>
</div>
<div class="chat-window">
<h5>{{ currentRoom }}</h5>
<ul class="message-list">
<li v-for="(message, index) in messages" :key="index" :class="{ 'message-own': message.from === username }">
<div class="username">{{ message.from }} <small>{{ message.createdAt | moment }}</small></div>
<div class="message">{{ message.message }}</div>
</li>
</ul>
<div class="input-group">
<input type="text" class="form-control" v-model="message" placeholder="输入消息" @keyup.enter="sendMessage">
<div class="input-group-append">
<button class="btn btn-primary" @click.prevent="sendMessage">发送</button>
</div>
</div>
</div>
<div class="chat-users">
<h5>用户列表({{ users.length }})</h5>
<ul>
<li v-for="(user, index) in users" :key="index">{{ user }}</li>
</ul>
</div>
</div>
</div>
</template>
<script>
import io from 'socket.io-client';
export default {
name: 'app',
data () {
return {
socket: null,
currentRoom: null,
message: '',
messages: [],
rooms: [],
users: [],
username: null,
};
},
filters: {
moment(str) {
return moment(new Date(str)).format("HH:mm:ss");
},
},
created() {
this.socket = io('http://localhost:3000');
// 监听socket.io事件
this.socket.on('connect', () => {
console.log(`[CLIENT] connected: ${this.socket.id}`);
});
this.socket.on('message', data => {
console.log(`[CLIENT] message received: ${data.message}`);
this.messages.push(data);
this.scrollMessageList();
});
this.socket.on('user update', data => {
console.log(`[CLIENT] user update received: ${JSON.stringify(data)}`);
this.fetchUsers();
});
this.socket.on('room update', data => {
console.log(`[CLIENT] room update received: ${JSON.stringify(data)}`);
this.rooms = data;
});
this.socket.on('room joined', data => {
this.currentRoom = data;
this.fetchMessages();
});
},
mounted() {
this.username = prompt('请输入您的用户名');
if (!this.username) {
alert('用户名不能为空');
window.location.reload();
}
this.fetchRooms();
this.fetchUsers();
},
methods: {
sendMessage() {
if (!this.message) {
return;
}
this.socket.emit('message', this.message);
this.message = '';
},
joinRoom(room) {
this.socket.emit('join room', {
name: this.username,
room: room
});
this.messages = [];
},
fetchMessages() {
this.messages = [];
axios.get(`/api/chat/messages/${this.currentRoom}`).then(res => {
this.messages = res.data[0].messages;
setTimeout(() => {
this.scrollMessageList();
}, 100);
}).catch(err => {
console.error(`[CLIENT ERROR] ${err}`);
});
},
fetchRooms() {
axios.get('/api/chat/rooms').then(res => {
this.rooms = res.data[0].rooms;
}).catch(err => {
console.error(`[CLIENT ERROR] ${err}`);
});
},
fetchUsers() {
axios.get(`/api/chat/users/${this.currentRoom}`).then(res => {
this.users = res.data;
}).catch(err => {
console.error(`[CLIENT ERROR] ${err}`);
});
},
scrollMessageList() {
let $messageList = this.$el.querySelector('.message-list');
$messageList.scrollTop = $messageList.scrollHeight;
},
},
};
</script>
<style>
...
</style>
4.完整示例说明
以上就是实现“vue+socket.io+express+mongodb 实现简易多房间在线群聊”示例的全部步骤。具体实现的过程中,需要注意以下几点:
- 确保服务端和客户端socket.io版本一致
- 服务端的socket.io要监听客户端的连接事件,客户端要监听与服务端的连接事件
- 服务端实现socket.io事件响应时,可以根据事件名称实现不同的功能。例如本示例中,
message
事件是用于处理发送消息,join room
和leave room
事件用于处理加入和退出房间 - 客户端实现socket.io事件响应时,可以在Vue模板中嵌入相关代码,例如本示例中,
message
事件响应代码直接更新messages数组中的内容即可在视图中渲染消息 - 注意安全问题,例如用户输入的消息、用户名等需要进行合法性验证,防止恶意攻击;同时还要避免在客户端处理不安全的操作,例如Vue模板中嵌入HTML代码等操作
以上就是本示例的完整攻略,希望本次讲解能对您有所帮助!
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:vue+socket.io+express+mongodb 实现简易多房间在线群聊示例 - Python技术站