vue+socket.io+express+mongodb 实现简易多房间在线群聊示例

yizhihongxing

下面我将详细讲解“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 roomleave room事件用于处理加入和退出房间
  • 客户端实现socket.io事件响应时,可以在Vue模板中嵌入相关代码,例如本示例中,message事件响应代码直接更新messages数组中的内容即可在视图中渲染消息
  • 注意安全问题,例如用户输入的消息、用户名等需要进行合法性验证,防止恶意攻击;同时还要避免在客户端处理不安全的操作,例如Vue模板中嵌入HTML代码等操作

以上就是本示例的完整攻略,希望本次讲解能对您有所帮助!

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:vue+socket.io+express+mongodb 实现简易多房间在线群聊示例 - Python技术站

(0)
上一篇 2023年5月25日
下一篇 2023年5月25日

相关文章

  • 利用mongodb查询某坐标是否在规定多边形区域内的方法

    要利用mongodb查询某坐标是否在规定多边形区域内,需要使用mongodb的地理空间功能。在mongodb中,我们可以将地理空间数据存储为GeoJSON格式,针对该格式的数据有丰富的地理空间查询功能。下面是实现步骤: 定义地理位置字段 在mongodb中,使用GeoJSON格式来表示地理位置数据。所以,在数据表中要定义一个字段专门存储GeoJSON格式的数…

    人工智能概论 2023年5月25日
    00
  • django 邮件发送模块smtp使用详解

    Django 邮件发送模块SMTP使用详解 概述 Django 自带了邮件发送模块,可以通过 SMTP 协议将邮件发送出去。本教程将详细讲解 Django 如何配置和使用 SMTP 协议发送邮件。 配置 在 Django 项目配置文件 settings.py 中进行 SMTP 邮件发送模块的配置。 # SMTP 邮件服务器地址 EMAIL_HOST = ‘s…

    人工智能概览 2023年5月25日
    00
  • Ubuntu系统搭建django+nginx+uwsgi的教程详解

    《Ubuntu系统搭建django+nginx+uwsgi的教程详解》 简介 本教程旨在帮助初学者使用Ubuntu系统快速搭建Django+nginx+uwsgi的开发环境。其中Django作为Python的一个Web框架,主要用于快速开发和部署网站应用程序。Nginx是一个高性能的Web服务器,可以使用反向代理和负载均衡等功能。而UWSGI则是一种功能强大…

    人工智能概览 2023年5月25日
    00
  • Nginx 请求压缩的实现(动态压缩,静态压缩)

    实现 Nginx 请求压缩可以大大减少网络传输时间和带宽使用,提高网站性能。Nginx 支持动态压缩和静态压缩两种方式来实现请求压缩,下面是详细的实现攻略。 动态压缩 动态压缩指的是在 Nginx 服务器上动态生成页面时,将页面内容压缩后返回给客户端浏览器。常用的压缩方式包括 Gzip 和 Brotli。 第一步:安装压缩模块 首先需要在 Nginx 上安装…

    人工智能概览 2023年5月25日
    00
  • 在django-xadmin中APScheduler的启动初始化实例

    在Django-xadmin中使用APScheduler可以很方便地实现后台任务,如定时任务、计划任务等。本篇攻略将详细讲解在django-xadmin中APScheduler的启动初始化实例的过程。 安装APScheduler 在使用APScheduler之前,需要先安装它。可以通过pip命令来进行安装: pip install apscheduler 配…

    人工智能概览 2023年5月25日
    00
  • TensorFlow 输出checkpoint 中的变量名与变量值方式

    TensorFlow 可以把某个时间点的模型保存到 checkpoint 文件。可以使用 TensorBoard 来可视化 checkpoint,或者通过 TensorFlow API 以编程方式获取 checkpoint 中变量的值。下面分步骤详细讲解 TensorFlow checkpoint 输出变量名和变量值的方式。 1. TensorFlow ch…

    人工智能概论 2023年5月24日
    00
  • 详解Redis 数据类型

    详解 Redis 数据类型 Redis 是一种高性能的键值存储数据库,支持多种数据类型。本文将详细讲解 Redis 的数据类型,包括字符串、哈希、列表、集合和有序集合。 字符串 字符串是 Redis 最基本的数据类型,它们可以存储任何类型的数据,包括数字和字母。字符串的最大长度是 512MB。 代码示例 以下是一个字符串类型的示例: SET mykey &q…

    人工智能概论 2023年5月25日
    00
  • Django利用AJAX技术实现博文实时搜索

    下面是Django利用AJAX技术实现博文实时搜索的完整攻略: 1. 实现思路 实现实时搜索功能的基本思路如下: 客户端输入关键字并提交; 查询数据库并返回结果; 客户端显示查询结果。 而在使用AJAX技术实现实时搜索时,可以使用以下步骤: 客户端监听输入框的keypress事件(即当用户在输入框中输入字符时); 监听到事件后,通过AJAX异步请求后台数据(…

    人工智能概论 2023年5月25日
    00
合作推广
合作推广
分享本页
返回顶部