首页 web前端 js教程 node+express实现聊天室

node+express实现聊天室

Mar 23, 2018 pm 03:00 PM
实现 聊天室

这次给大家带来node+express实现聊天室,node+express实现聊天室的注意事项有哪些,下面就是实战案例,一起来看一下。

本篇文章使用node+express+jquery写一个个性化聊天室,一起来get一下~(源码地址见文章末尾)

效果图

项目结构

实现功能

  1. 登录检测

  2. 系统自动提示用户状态(进入/离开)

  3. 显示在线用户

  4. 支持发送和接收消息

  5. 自定义字体颜色

  6. 支持发送表情

  7. 支持发送图片

下面将一一讲解如何实现

前期准备

node及npm环境、express、socket.io

具体实现

1、将聊天室部署到服务器

先用node搭建一个服务器,部署在localhost:3000端口,先尝试向浏览器发送一个“hello world”,新建server.js文件。

var app = require('express')(); // 引入express模块
var http = require('http').Server(app);
app.get('/', function(req, res){ // 路由为localhost:3000时向客户端响应“hello world”
 res.send('<h1>Hello world</h1>'); // 发送数据
});
http.listen(3000, function(){ // 监听3000端口
 console.log('listening on *:3000'); 
});
登录后复制

打开浏览器输入网址:localhost:3000是这样的

一个node服务器搭建成功。

接下来用express向浏览器返回一个html页面

#安装express模块
npm install --save express
登录后复制

将server.js的代码改一下:

var express = require('express');
var app = express();
var http = require('http').Server(app); 
// 路由为/默认www静态文件夹
app.use('/', express.static(dirname + '/www'));
登录后复制

express.static(dirname + '/www');是将www文件夹托管为静态资源,意味着这个文件夹里的文件(html、css、js)彼此可以用相对路径。在www文件夹中添加index.html文件以及相应的css(相应css代码就不贴了,详情见源码),如下,该页面用了font-awesome小图标

<!doctype html>
<html>
 <head>  
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <title>chat</title>
 <link rel="stylesheet" href="style/index.css" rel="external nofollow" >
 <link rel="stylesheet" href="style/font-awesome-4.7.0/css/font-awesome.min.css" rel="external nofollow" >
 </head>
 <body>
 <p class="all">
  <p class="name">
  <!-- <h2>请输入你的昵称</h2> -->
  <input type="text" id="name" placeholder="请输入昵称..." autocomplete="off"> 
  <button id="nameBtn">确 定</button>
  </p>
  <p class="main">
  <p class="header">
   <img src="image/logo.jpg">
   happy聊天室
  </p>
  <p id="container">
   <p class="conversation">
    <ul id="messages"></ul>
    <form action="">
     <p class="edit"> 
     <input type="color" id="color" value="#000000">
     <i title="双击取消选择" class="fa fa-smile-o" id="smile">
     </i><i title="双击取消选择" class="fa fa-picture-o" id="img"></i>
     <p class="selectBox"> 
      <p class="smile"> 
      </p>
      <p class="img"> 
      </p>
     </p>
     </p>
     <!-- autocomplete禁用自动完成功能 -->
     <textarea id="m"></textarea>
     <button class="btn rBtn" id="sub">发送</button>
     <button class="btn" id="clear">关闭</button>
    </form>
   </p>
   <p class="contacts">
   <h1>在线人员(<span id="num">0</span>)</h1>
   <ul id="users"></ul>
   <p>当前无人在线哟~</p>
   </p>
  </p>
  </p> 
 </p> 
 </body>
</html>
登录后复制

打开localhost:3000,会看到如下:

聊天室成功部署到服务器。

2、检测登录

在客户端和服务器之间传送消息需要用到socket.io

#安装socket.io模块
npm install --save socket.io
登录后复制

将server.js改动如下:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.use('/', express.static(dirname + '/www'));
io.on('connection', function(socket){ // 用户连接时触发
 console.log('a user connected');
});
http.listen(3000, function(){
 console.log('listening on *:3000');
});
登录后复制

当打开localhost:3000的时候会触发服务器端io的connection事件,会在服务器打印“a user connected”,但是我们想统计一下连接该服务器的用户人数,如果有用户连接就打印“n users connected”,n为用户人数,怎么办呢?

在server.js设置一个全局数组为user,每当一个用户连接成功就在连接事件中将用户的昵称push进user,打印user.length即可知道已成功连接用户的人数。

等一等。

在用户连接的时输入昵称登录,我们应该检测一下用户的昵称是否已存在,避免昵称相同的情况发生,在服务器监听一个登录事件来判断该情况,由于一切都发生在用户连接之后,所以触发事件应该写在connection事件的回调函数中。

io.on('connection', (socket)=> {
 // 渲染在线人员
 io.emit('disUser', usersInfo);
 // 登录,检测用户名
 socket.on('login', (user)=> {
  if(users.indexOf(user.name) > -1) { // 昵称是否存在
   socket.emit('loginError'); // 触发客户端的登录失败事件
  } else {
   users.push(user.name); //储存用户的昵称
   usersInfo.push(user); // 储存用户的昵称和头像
   socket.emit('loginSuc'); // 触发客户端的登录成功事件
   socket.nickname = user.name;
   io.emit('system', { // 向所有用户广播该用户进入房间
    name: user.name,
    status: '进入'
   });
   io.emit('disUser', usersInfo); // 渲染右侧在线人员信息
   console.log(users.length + ' user connect.'); // 打印连接人数
  }
 });
登录后复制

system和disUser事件先不管,之后再说 区分io.emit(foo)、socket.emit(foo)、socket.broadcast.emit(foo)

io.emit(foo); //会触发所有客户端用户的foo事件
socket.emit(foo); //只触发当前客户端用户的foo事件
socket.broadcast.emit(foo); //触发除了当前客户端用户的其他用户的foo事件
登录后复制

接下来是客户端代码chat-client.js

$(function() {
  // io-client
  // 连接成功会触发服务器端的connection事件
  var socket = io();
  // 点击输入昵称
  $('#nameBtn').click(()=> { 
   var imgN = Math.floor(Math.random()*4)+1; // 随机分配头像
   if($('#name').val().trim()!=='')
     socket.emit('login', { // 触发服务器端登录事件
      name: $('#name').val(),
      img: 'image/user' + imgN + '.jpg'
     }); 
   return false; 
  });
  // 登录成功,隐藏登录层
  socket.on('loginSuc', ()=> { 
   $('.name').hide(); 
  })
  socket.on('loginError', ()=> {
   alert('用户名已存在,请重新输入!');
   $('#name').val('');
  }); 
});
登录后复制

倘若登录成功,会看到如下页面:

登录检测完成。

3、系统自动提示用户状态(进入/离开)

该功能是为了实现上图所示的系统提示“XXX进入聊天室”,在登录成功时触发system事件,向所有用户广播信息,注意此时用的是io.emit而不是socket.emit,客户端代码如下

// 系统提示消息
socket.on('system', (user)=> { 
 var data = new Date().toTimeString().substr(0, 8);
 $('#messages').append(`<p class=&#39;system&#39;><span>${data}</span><br /><span>${user.name} ${user.status}了聊天室<span></p>`);
 // 滚动条总是在最底部
 $('#messages').scrollTop($('#messages')[0].scrollHeight);
});
登录后复制

4、显示在线用户

客户端监听一个显示在线用户的事件disUser,在以下三个时间段服务器端就触发一次该事件重新渲染一次

  1. 程序开始启动时

  2. 每当用户进入房间

  3. 每当用户离开房间

// chat-client.js
// 显示在线人员
socket.on('disUser', (usersInfo)=> {
 displayUser(usersInfo);
});
// 显示在线人员
function displayUser(users) {
 $('#users').text(''); // 每次都要重新渲染
 if(!users.length) {
  $('.contacts p').show();
 } else {
  $('.contacts p').hide();
 }
 $('#num').text(users.length);
 for(var i = 0; i < users.length; i++) {
  var $html = `<li>
   <img src="${users[i].img}">
   <span>${users[i].name}</span>
  </li>`;
  $('#users').append($html);
 }
}
登录后复制

5、支持发送和接收消息

用户发送消息时触发服务器端的sendMsg事件,并将消息内容作为参数,服务器端监听到sendMsg事件之后向其他所有用户广播该消息,用的socket.broadcast.emit(foo)

 // server.js
  // 发送消息事件
  socket.on('sendMsg', (data)=> {
    var img = '';
    for(var i = 0; i < usersInfo.length; i++) {
      if(usersInfo[i].name == socket.nickname) {
        img = usersInfo[i].img;
      }
    }
    socket.broadcast.emit(&#39;receiveMsg&#39;, { // 向除了发送者之外的其他用户广播
      name: socket.nickname,
      img: img,
      msg: data.msg,
      color: data.color,
      side: &#39;left&#39;
    });
    socket.emit(&#39;receiveMsg&#39;, { // 向发送者发送消息,为什么分开发送?因为css样式不同
      name: socket.nickname,
      img: img,
      msg: data.msg,
      color: data.color,
      side: &#39;right&#39;
    });
  });
登录后复制

服务器端接受到来自用户的消息后会触发客户端的receiveMsg事件,并将用户发送的消息作为参数传递,该事件会向聊天面板添加聊天内容,以下为chat-client.js代码

// 点击按钮或回车键发送消息
  $(&#39;#sub&#39;).click(sendMsg);
  $(&#39;#m&#39;).keyup((ev)=> {
   if(ev.which == 13) {
    sendMsg();
   }
  });
  // 接收消息
  socket.on('receiveMsg', (obj)=> { // 将接收到的消息渲染到面板上
   $('#messages').append(` 
     <li class=&#39;${obj.side}&#39;>
     <img src="${obj.img}">
     <p>
      <span>${obj.name}</span>
      <p>${obj.msg}</p>
     </p>
    </li>
   `);
   // 滚动条总是在最底部
   $('#messages').scrollTop($('#messages')[0].scrollHeight);
  });
  // 发送消息
  function sendMsg() { 
   if($('#m').val() == '') { // 输入消息为空
    alert('请输入内容!');
    return false;
   }
   socket.emit('sendMsg', {
    msg: $('#m').val()
   });
   $('#m').val(''); 
   return false; 
  }
登录后复制

6、自定义字体颜色

得益于html5的input新特性,可以通过type为color的input调用系统调色板

<!-- $(&#39;#color&#39;).val();为选中颜色,格式为#FFCCBB -->
<input type=&#39;color&#39; id=&#39;color&#39;>
登录后复制

客户端根据用户选择的颜色渲染内容样式,代码很容易看懂,这里就不赘述了。

7、支持发送表情

发送表情其实很简单,将表情图片放在li中,当用户点击li时就将表情的src中的序号解析出来,用[emoji+表情序号]的格式存放在聊天框里,点击发送后再解析为src。就是一个解析加还原的过程,这一过程中我们的服务器代码不变,需要改变的是客户端监听的receiveMsg事件。

// chat-client.js
  // 显示表情选择面板
  $('#smile').click(()=> {
   $('.selectBox').css('display', "block");
  });
  $('#smile').dblclick((ev)=> { 
   $('.selectBox').css('display', "none");
  }); 
  $('#m').click(()=> {
   $('.selectBox').css('display', "none");
  });
  // 用户点击发送表情
  $('.emoji li img').click((ev)=> {
    ev = ev || window.event;
    var src = ev.target.src;
    var emoji = src.replace(/\D*/g, '').substr(6, 8); // 提取序号
    var old = $('#m').val(); // 用户输入的其他内容
    $('#m').val(old+'[emoji'+emoji+']');
    $('.selectBox').css('display', "none");
  });
登录后复制

客户端收到之后将表情序号还原为src,更改如下

// chat-client.js
  // 接收消息
  socket.on('receiveMsg', (obj)=> { 
   // 提取文字中的表情加以渲染
   var msg = obj.msg;
   var content = '';
   while(msg.indexOf('[') > -1) { // 其实更建议用正则将[]中的内容提取出来
    var start = msg.indexOf('[');
    var end = msg.indexOf(']');
    content += '<span>'+msg.substr(0, start)+'</span>';
    content += '<img src="image/emoji/emoji%20(&#39;+msg.substr(start+6, end-start-6)+&#39;).png">';
    msg = msg.substr(end+1, msg.length);
   }
   content += '<span>'+msg+'</span>';
   
   $('#messages').append(`
    <li class=&#39;${obj.side}&#39;>
     <img src="${obj.img}">
     <p>
      <span>${obj.name}</span>
      <p style="color: ${obj.color};">${content}</p>
     </p>
    </li>
   `);
   // 滚动条总是在最底部
   $('#messages').scrollTop($('#messages')[0].scrollHeight);
  });
登录后复制

可以成功发送表情了。

8、支持发送图片

首先是图片按钮样式,发送图片的按钮是type为file的input。这里有一个改变样式的小技巧,那就是将input的透明度设为0,z-index为5,将你想要得样式放在p中,z-index设为1覆盖在input上。

<input type="file" id="file">
<i class="fa fa-picture-o" id="img"></i>
css:
.edit #file {
  width: 32.36px;
  height: 29px;
  opacity: 0;
  z-index: 5;
}
.edit #img {
  z-index: 0;
  margin-left: -43px;
}
登录后复制

完美

接下来是点击按钮发送图片,我们用了fileReader对象,这里有一篇不错的文章讲解了fileReader,fileReader是一个对象,可以将我们选中的文件已64位输出然后将结果存放在reader.result中,我们选中图片之后,reader.result就存放的是图片的src

// chat-client.js
  // 用户发送图片
  $('#file').change(function() {
   var file = this.files[0]; // 上传单张图片
   var reader = new FileReader();
   //文件读取出错的时候触发
   reader.onerror = function(){
     console.log('读取文件失败,请重试!'); 
   };
   // 读取成功后
   reader.onload = function() {
    var src = reader.result; // 读取结果
    var img = '<img class="sendImg" src="&#39;+src+&#39;">';
    socket.emit('sendMsg', { // 发送
     msg: img,
     color: color,
     type: 'img' // 发送类型为img
    }); 
   };
   reader.readAsDataURL(file); // 读取为64位
  });
登录后复制

由于发送的是图片,所以对页面布局难免有影响,为了页面美观客户端在接收其他用户发送的消息的时候会先判断发送的是文本还是图片,根据不同的结果展示不同布局。判断的方法是在客户发送消息的时候传入一个type,根据type的值来确实发送内容的类型。所以上面发送图片代码中触发了sendMsg事件,传入参数多了一个type属性。

响应的,我们应该在chat-client.js中修改receiveMsg事件监听函数,改为根据传入type做不同操作

chat-client.js
  // 接收消息
  socket.on('receiveMsg', (obj)=> { 
   // 发送为图片
   if(obj.type == 'img') {
    $('#messages').append(`
     <li class=&#39;${obj.side}&#39;>
      <img src="${obj.img}">
      <p>
       <span>${obj.name}</span>
       <p style="padding: 0;">${obj.msg}</p>
      </p>
     </li>
    `); 
    $('#messages').scrollTop($('#messages')[0].scrollHeight);
    return;
   }
   // 提取文字中的表情加以渲染
   // 下面不变
  });
登录后复制

现在我们可以发送图片了

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

datepicker怎么使用

mixin的高阶组件使用详解

JS获取图片的top N色值方法

以上是node+express实现聊天室的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

华为手机如何实现双微信登录? 华为手机如何实现双微信登录? Mar 24, 2024 am 11:27 AM

华为手机如何实现双微信登录?随着社交媒体的兴起,微信已经成为人们日常生活中不可或缺的沟通工具之一。然而,许多人可能会遇到一个问题:在同一部手机上同时登录多个微信账号。对于华为手机用户来说,实现双微信登录并不困难,本文将介绍华为手机如何实现双微信登录的方法。首先,华为手机自带的EMUI系统提供了一个很便利的功能——应用双开。通过应用双开功能,用户可以在手机上同

使用Java编写代码实现爱心动画 使用Java编写代码实现爱心动画 Dec 23, 2023 pm 12:09 PM

通过Java代码实现爱心动画效果在编程领域中,动画效果是非常常见和受欢迎的。可以通过Java代码实现各种各样的动画效果,其中之一就是爱心动画效果。本文将介绍如何使用Java代码来实现这一效果,并给出具体的代码示例。实现爱心动画效果的关键在于绘制心形图案,并通过改变心形的位置和颜色来实现动画效果。下面是一个简单示例的代码:importjavax.swing.

PHP编程指南:实现斐波那契数列的方法 PHP编程指南:实现斐波那契数列的方法 Mar 20, 2024 pm 04:54 PM

编程语言PHP是一种用于Web开发的强大工具,能够支持多种不同的编程逻辑和算法。其中,实现斐波那契数列是一个常见且经典的编程问题。在这篇文章中,将介绍如何使用PHP编程语言来实现斐波那契数列的方法,并附上具体的代码示例。斐波那契数列是一个数学上的序列,其定义如下:数列的第一个和第二个元素为1,从第三个元素开始,每个元素的值等于前两个元素的和。数列的前几个元

如何在华为手机上实现微信分身功能 如何在华为手机上实现微信分身功能 Mar 24, 2024 pm 06:03 PM

如何在华为手机上实现微信分身功能随着社交软件的普及和人们对隐私安全的日益重视,微信分身功能逐渐成为人们关注的焦点。微信分身功能可以帮助用户在同一台手机上同时登录多个微信账号,方便管理和使用。在华为手机上实现微信分身功能并不困难,只需要按照以下步骤操作即可。第一步:确保手机系统版本和微信版本符合要求首先,确保你的华为手机系统版本已更新到最新版本,以及微信App

开发建议:如何利用ThinkPHP框架实现异步任务 开发建议:如何利用ThinkPHP框架实现异步任务 Nov 22, 2023 pm 12:01 PM

《开发建议:如何利用ThinkPHP框架实现异步任务》随着互联网技术的迅猛发展,Web应用程序对于处理大量并发请求和复杂业务逻辑的需求也越来越高。为了提高系统的性能和用户体验,开发人员常常会考虑利用异步任务来执行一些耗时操作,比如发送邮件、处理文件上传、生成报表等。在PHP领域,ThinkPHP框架作为一款流行的开发框架,提供了一些便捷的方式来实现异步任务。

如何使用Go语言开发Websocket聊天室 如何使用Go语言开发Websocket聊天室 Dec 14, 2023 pm 01:46 PM

如何使用Go语言开发Websocket聊天室Websocket是一种实时通信协议,通过建立一次连接,可以在服务器和客户端之间进行双向通信。在开发聊天室时,Websocket是一个非常好的选择,因为它可以实现实时消息交流,并且能够提供高效的性能。本文将介绍如何使用Go语言开发一个简单的Websocket聊天室,并提供一些具体的代码示例。一、准备工作1.安装Go

掌握Golang如何实现游戏开发的可能性 掌握Golang如何实现游戏开发的可能性 Mar 16, 2024 pm 12:57 PM

在当今的软件开发领域中,Golang(Go语言)作为一种高效、简洁、并发性强的编程语言,越来越受到开发者的青睐。其丰富的标准库和高效的并发特性使它成为游戏开发领域的一个备受关注的选择。本文将探讨如何利用Golang来实现游戏开发,并通过具体的代码示例来展示其强大的可能性。1.Golang在游戏开发中的优势作为一种静态类型语言,Golang在构建大型游戏系统

如何在Golang中实现精确除法运算 如何在Golang中实现精确除法运算 Feb 20, 2024 pm 10:51 PM

在Golang中实现精确除法运算是一个常见的需求,特别是在涉及金融计算或其它需要高精度计算的场景中。Golang的内置的除法运算符“/”是针对浮点数计算的,并且有时会出现精度丢失的问题。为了解决这个问题,我们可以借助第三方库或自定义函数来实现精确除法运算。一种常见的方法是使用math/big包中的Rat类型,它提供了分数的表示形式,可以用来实现精确的除法运算

See all articles