WebSocket+NodeJS实现简单的聊天室功能

本文介绍了如何使用Node.js、Express和Socket.IO创建一个简单的多用户聊天室,包括初始化项目、设置依赖、设计用户界面、实现WebSocket连接以及处理消息转发和静态资源的管理。
摘要由CSDN通过智能技术生成

效果图:

select user

user1

user2

user3

imageuser4

1. 创建一个package.json,搭建本项目初始依赖

npm init -y

// 填写package.json的对应内容
{
  "name": "websocket-express-webchat",
  "version": "1.0.1",
  "description": "基于websocket的一个简单的聊天室",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.14.1",
    "socket.io": "^1.7.2"
  }
}

// 填写完成后使用npm i 或 yarn add 下载项目依赖

2. 新建角色选择页面,可以选择不同的角色

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ws聊天室</title>
    <link href="/public/base.css" />
    <style>
      .title {
        text-align: center;
        margin-top: 100px;
      }
      .userList {
        display: flex;
        justify-content: center;
        list-style: none;
        flex-wrap: wrap;
      }
      .userList li {
        flex: 1;
        float: left;
        margin: 20px;
        background-color: #5bd1d7;
        text-align: center;
        border-radius: 20px;
        line-height: 200px;
        cursor: pointer;
      }
      .userList li a {
        display: block;
        width: 100%;
        height: 100%;
        color: #515bd4;
        text-decoration: none;
      }
    </style>
  </head>
  <body>
    <h1 class="title">请选择您的角色</h1>
    <ul class="userList">
      <li><a href="/user1">user1</a></li>
      <li><a href="/user2">user2</a></li>
      <li><a href="/user3">user3</a></li>
      <li><a href="/user4">user4</a></li>
    </ul>
  </body>
</html>

3. 新建public文件夹,存储静态资源部分

websocket-express-webchat
│
├── node-modules/
│
├── public/
│   ├── img/
│   │   └── user1.jpg
│   │   └── user2.jpg
│   │   └── user3.jpg
│   │   └── user4.jpg
│   └── base.css
│   └── user.css
│   └── user1.html
│   └── user2.html
│   └── user3.html
│   └── user4.html
│
└── app.js
└── index.html
└── app.js

4. 搭建各个用户界面

// user1.html,user2.html,user3.html,user4.html通用,只需要根据内部注释实时修改user的值为1,2,3,4即可
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="./base.css" />
    <link rel="stylesheet" href="./user.css" />
    <title>Document</title>
  </head>
  <body>
    <div class="chatBody"></div>
    <div class="chatBox">
      <input type="text" name="" id="" cols="30" rows="10" placeholder="请输入内容" class="textarea" />
      <div class="btn">发送</div>
    </div>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      const btn = document.querySelector('.btn');
      const textarea = document.querySelector('.textarea');
      const chatBody = document.querySelector('.chatBody');
      const imgList = ['./img/user1.jpg', './img/user2.jpg', './img/user3.jpg', './img/user4.jpg'];

      // 通过io第三方库与websocket建立连接
      const ws = io('http://localhost:3000');

      // 自定义事件,当websocket调用news方法时这里的回调函数执行,并携带对应的参数
      ws.on('news', data => {
        // 这里如果是user1,则判断data.user===1,反之为user2.则判断data.user===2......
        if (data.user === 1) return;
        chatBody.innerHTML += generateStr('left', imgList[data.user - 1], data.content, data.time);
      });
      ws.onopen = function () {
        console.log(ws.readyState, '连接成功');
      };
      ws.onclose = function () {
        console.log('取消连接');
      };
      ws.onerror = function (err) {
        console.log('连接错误', err);
      };
      ws.onmessage = function (msg) {
        console.log('接收消息msg', msg);
      };
      let str = '';
      // textarea输入内容时触发
      textarea.addEventListener('input', e => {
        str = textarea.value;
      });

      // 发布消息函数
      const publicMessage = () => {
        if (str.trim().length !== 0) {
          chatBody.innerHTML += generateStr('right', imgList[0], str, new Date());

          // 调用websocket自定义的sendMsg方法,并传递对应的数据
          ws.emit('sendMsg', {
            content: str,
            // 这里表示当前用户的id,会在发送消息时携带过去,用于标识当前的用户,当前如果为user1.html,这里的值就为user: 1,如果为user2.html,这里的值就为user: 2
            user: 1,
            time: new Date(),
          });
        }
        str = '';
        textarea.value = '';
        chatBody.scrollTo({
          top: chatBody.scrollHeight,
          behavior: 'smooth',
        });
      };

      textarea.addEventListener('keydown', e => {
        if (e.keyCode === 13) {
          // 发布
          publicMessage();
        }
      });

      // 生成html字符串,用于填充进chatBody中
      const generateStr = (type, img, value, time) => {
        return type === 'right'
          ? `<div class="right">
                <div class="text">
                  <p>${value}</p>
                  <p>${format(time, 'yyyy-MM-dd hh:mm:ss')}</p>
                 </div>
              <img src="${img}" alt="" />
             </div>`
          : `<div class="left">
              <img src="${img}" alt="" />
                <div class="text">
                  <p>${value}</p>
                  <p>${format(time, 'yyyy-MM-dd hh:mm:ss')}</p>
                </div>
             </div>`;
      };

      // 点击发布时触发
      btn.addEventListener('click', publicMessage);

      // 日期格式化函数
      function format(date, fmt) {
        if (date instanceof Date) return '';
        let time = new Date(date);
        const o = {
          'M+': time.getMonth() + 1,
          'd+': time.getDate(),
          'h+': time.getHours(),
          'm+': time.getMinutes(),
          's+': time.getSeconds(),
          'q+': Math.floor((time.getMonth() + 3) / 3),
          S: time.getMilliseconds(),
        };
        if (/(y+)/.test(fmt)) {
          fmt = fmt.replace(RegExp.$1, (time.getFullYear() + '').substr(4 - RegExp.$1.length));
        }
        for (let k in o) {
          if (new RegExp('(' + k + ')').test(fmt)) {
            fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length));
          }
        }
        return fmt;
      }
    </script>
  </body>
</html>

5. 新建app.js文件,使用node环境启动,负责websocket消息的接收与转发以及开发服务器的启动

// app.js
// 引入express库
var express = require('express');
// 引入socket.io库用于实现websocket通信
var socket = require('socket.io');
// 设置文件根路径
var path = __dirname + '/public'

// 创建并启动服务器
var app = express();
var server = app.listen(3000, () => {
  console.log(`http://localhost:3000`);
});

// 创建websocket实例,并与服务器进行关联
var ws = new socket(server);

// 处理websocket事件
ws.on('connection', (socket) => {
  // websocket收到sendMsg事件时调用这里的回调函数(senhdMsg是某个页面发送消息的事件)
  socket.on('sendMsg', (data) => {
    // 当页面发送消息时,就将收到的消息进行广播,所以连接词websocket的页面都可以收到
    ws.sockets.emit('news', data);
  })
});

// 处理静态文件请求
app.use(express.static(path));


// 处理路由请求
app.get('/', (req, res) => {
  // 返回 index.html 页面
  res.sendFile(__dirname + '/index.html');
});

// 处理 user1 页面请求
app.get('/user1', (req, res) => {
  // 返回 user1.html 页面
  res.sendFile(path + '/user1.html');
});
// 处理 user2 页面请求
app.get('/user2', (req, res) => {
  // 返回 user2.html 页面
  res.sendFile(path + '/user2.html');
});
// 处理 user3 页面请求
app.get('/user3', (req, res) => {
  // 返回 user3.html 页面
  res.sendFile(path + '/user3.html');
});
// 处理 user4 页面请求
app.get('/user4', (req, res) => {
  // 返回 user4.html 页面
  res.sendFile(path + '/user4.html');
});

// 处理第三方库请求
// 使用静态文件中间件,设置第三方库路径
app.use(express.static('node_modules'));

6. 启动app.js

// 在当前项目的目录下终端启动输入命令
node app.js

// 根据终端提示的url信息,访问页面即可实现聊天室效果
  • 19
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值