Node.js+express+socket實(shí)現(xiàn)在線實(shí)時(shí)多人聊天室
本文實(shí)例為大家分享了Node.js+express+socket實(shí)現(xiàn)在線實(shí)時(shí)多人聊天室的具體代碼,供大家參考,具體內(nèi)容如下
文件結(jié)構(gòu)如下:

前端部分:
登錄頁(yè)面Login部分:
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>login</title>
<link rel="stylesheet" href="css/login.css" >
</head>
<body>
<div class="login-box flex-box">
<!--登錄標(biāo)題欄-->
<h2 class="sign-title box-width">LOGIN</h2>
<!--頭像欄-->
<div class="picture-carousel">
<div class="arrow left-arrow">
<div class="before-arrow"></div>
</div>
<img class="p1 img-setting" src="./img/1.jpg" alt="1.jpg">
<img class="p2 img-setting" src="./img/2.jpg" alt="2.jpg">
<img class="p3 img-setting" src="./img/3.jpg" alt="3.jpg">
<img class="p2 img-setting" src="./img/4.jpg" alt="4.jpg">
<img class="p1 img-setting" src="./img/5.jpg" alt="5.jpg">
<div class="arrow right-arrow">
<div class="after-arrow"></div>
</div>
</div>
<!--用戶名欄-->
<div class="name-box box-width">
<input type="text" class="user-name box-width" placeholder="Please Type Your Name">
</div>
<!--確認(rèn)欄-->
<div class="button-box box-width">
<input type="button" class="login-button box-width" value="Login The Chatroom">
</div>
<!--錯(cuò)誤信息欄-->
<div class="error-box box-width">
<span class="error-message">Welcome to chatroom!</span>
</div>
</div>
</body>
<script src="js/login.js"></script>
</html>
login.css
* {
padding: 0;
margin: 0;
font-family: "Microsoft Yahei";
}
html,
body {
width: 100%;
height: 100%;
font-family: "Microsoft Yahei";
display: flex;
justify-content: center;
align-items: center;
}
body {
background: linear-gradient(-135deg, #51D15B, #42A855);
background: -moz-linear-gradient(-135deg, #51D15B, #42A855);
background: -webkit-linear-gradient(-135deg, #51D15B, #42A855);
background: -o-linear-gradient(-135deg, #51D15B, #42A855);
}
.flex-box {
display: flex;
justify-content: center;
align-items: center;
}
.box-width {
width: 80%;
}
/*最外層*/
.login-box {
width: 20%;
min-width: 304px;
max-width: 404px;
height: 50%;
min-height: 368px;
max-height: 468px;
flex-direction: column;
box-shadow: 1px 1px 15px #7B8C99;
background: #fff;
}
/*LOGIN標(biāo)題*/
.sign-title {
color: #42A855;
border: 2px solid #42A855;
border-top: transparent;
border-left: transparent;
border-right: transparent;
}
/*圖片切換*/
.picture-carousel {
position: relative;
display: flex;
margin: 10%;
}
/*圖片切換箭頭*/
.arrow {
z-index: 3;
position: absolute;
font-size: 60px;
height: 100%;
width: 30%;
display: flex;
justify-content: center;
align-items: center;
color: #ffffff;
}
.arrow:hover {
cursor: pointer;
}
.left-arrow {
left: 0;
}
.before-arrow {
width: 0px;
height: 0px;
border-width: 30px;
border-style: solid;
border-color: transparent #51D15B transparent transparent;
}
.right-arrow {
right: 0;
}
.after-arrow{
width: 0px;
height: 0px;
border-width: 30px;
border-style: solid;
border-color: transparent transparent transparent #51D15B;
}
.picture-carousel img {
width: 80px;
height: 80px;
transition: all 0.2s linear;
-moz-transition: all 0.2s ease-out;
-webkit-transition: all 0.2s ease-out;
-o-transition: all 0.2s ease-out;
}
.img-setting {
margin: 0px -15px;
}
.p1 {
transform: scale(0.6);
z-index: 1;
}
.p1:hover {
transform: scale(0.8);
}
.p2 {
transform: scale(0.8);
z-index: 2;
}
.p2:hover {
transform: scale(1);
}
.p3 {
transform: scale(1);
z-index: 3;
}
.p3:hover {
transform: scale(1.2);
}
/*用戶名*/
.name-box {
display: flex;
justify-content: center;
border: 1px solid #51D15B;
}
.name-box .user-name {
width: 100%;
text-align: center;
padding: 10px;
outline-color: #42A855;
border: none;
font-size: 16px;
}
/* 登錄按鈕 */
.button-box{
display: flex;
justify-content: center;
margin: 10px 0 20px;
}
.button-box .login-button{
width: 100%;
padding: 10px 20px;
outline:none;
border: none;
background: #42A855;
color: white;
font-size: 16px;
}
/* 錯(cuò)誤信息 */
.error-box{
color: #42A855;
border: 2px solid #42A855;
border-top: transparent;
border-left: transparent;
border-right: transparent;
}
.error-box span{
visibility: hidden;
color: #d43f3a;
font-size: 14px;
}
login.js
// 用于存儲(chǔ)圖片順序
var imgArray = ['1','2','3','4','5'];
// 獲取箭頭
var leftArrow = document.getElementsByClassName('left-arrow')[0];
var rightArrow = document.getElementsByClassName('right-arrow')[0];
// 獲取用戶名
var userName = document.getElementsByClassName('user-name')[0];
// 獲取登錄按鈕
var loginButton = document.getElementsByClassName('login-button')[0];
// 獲取錯(cuò)誤信息欄
var errorMessage = document.getElementsByClassName('error-message')[0];
// 添加左箭頭監(jiān)聽(tīng)事件
leftArrow.addEventListener('click',function(){
imgArray.unshift(imgArray[imgArray.length - 1]); // 向數(shù)組的開(kāi)頭添加一個(gè)元素 //
imgArray.pop(); // 刪除并返回?cái)?shù)組的最后一個(gè)元素
carouselImg(); // 切換圖片
});
// 添加右箭頭監(jiān)聽(tīng)事件
rightArrow.addEventListener('click',function(){
imgArray.push(imgArray[0]); // 把第一個(gè)元素放在最后
imgArray.shift(); // 刪除并返回?cái)?shù)組的第一個(gè)元素
carouselImg(); // 切換圖片
});
// 切換圖片
function carouselImg(){
for(var count = 0;count < imgArray.length;count++){
document.getElementsByTagName('img')[count].src = './img/' + imgArray[count] + '.jpg';
document.getElementsByTagName('img')[count].alt=imgArray[count] + '.jpg';
}
}
// 添加登錄按鈕監(jiān)聽(tīng)事件
loginButton.addEventListener('click',function(){
if(userName.value === ''){
errorMessage.innerHTML = 'Please Type You Name';
errorMessage.style.visibility = 'visible';
}else if(userName.value.length > 8){
errorMessage.innerHTML = 'Your Name Cannot Over 8 Words';
errorMessage.style.visibility = 'visible';
}else{
window.location.href=encodeURI('index.html?selectpicture=' + document.getElementsByClassName('p3')[0].alt +
'&username=' + userName.value);
}
});
// Enter按鍵綁定登錄事件
document.onkeydown = function (event) {
var e = event || window.event;
if(e && e.keyCode === 13){
loginButton.click();
}
};
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>chat-room</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="./css/index.css" />
</head>
<body>
<div class="chat-box">
<!-- 聊天框頭部 -->
<div class="chat-header">
<div class="button-box">
<input type="button" class="log-out" value="LOGOUT" />
</div>
</div>
<!-- 聊天框主體 -->
<div class="chat-body">
<!-- 聊天框左側(cè) -->
<div class="chat-body-left">
<!-- 聊天框左側(cè)聊天內(nèi)容 -->
<div class="chat-content"></div>
<!-- 聊天框左側(cè)聊天輸入框 -->
<div class="chat-edit">
<input type="text" class="edit-box" placeholder="Please Type You Message" maxlength="15"/>
<input type="button" class="edit-button" value="SEND" />
</div>
</div>
<!-- 聊天框右側(cè) -->
<div class="chat-body-right">
<!-- 聊天框右側(cè)統(tǒng)計(jì)人數(shù) -->
<div class="online-count">Online:0</div>
<!-- 聊天框右側(cè)用戶名 -->
<div class="user-name">user-name</div>
<!-- 聊天框右側(cè)頭像 -->
<img class="user-img" />
</div>
</div>
</div>
</body>
</html>
<script src="./js/socket.io.js"></script>
<script src="./js/index.js"></script>
index.css
*{
margin: 0;
padding: 0;
font-family: "Microsoft Yahei"
}
html,body{
width: 100%;
height: 100%;
}
/* 背景色 */
body{
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(-135deg,#51D15B,#42A855);
background: -moz-linear-gradient(-135deg,#51D15B,#42A855);
background: -webkit-linear-gradient(-135deg,#51D15B,#42A855);
background: -o-linear-gradient(-135deg,#51D15B,#42A855);
}
/* 最外層 */
.chat-box{
width: 50%;
max-width: 720px;
min-width: 400px;
height: 80%;
min-height: 530px;
max-height: 530px;
display: flex;
flex-direction: column;
background: #fff;
box-shadow: 1px 1px 15px #333;
}
/* 頭部 */
.chat-header{
margin: 5px;
box-shadow: 1px 1px 15px #7B8C99;
}
.button-box{
display: flex;
justify-content: flex-end;
}
.log-out{
height: 100%;
font-size: 14px;
font-weight: bold;
padding: 5px 15px;
color: #79C2EA;
background: #fff;
outline: none;
border: none;
border-radius: 15px;
cursor: pointer;
}
/* 主體 */
.chat-body{
height: 90%;
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;
margin: 5px;
padding: 5px;
}
/* 主體左側(cè) */
.chat-body-left{
height: 100%;
width: 70%;
display: flex;
flex-direction: column;
justify-content: space-around;
margin: 5px;
}
/* 左側(cè)內(nèi)容 */
.chat-content{
box-shadow: 1px 1px 15px #7B8C99;
height: 100%;
margin-bottom: 5px;
overflow: scroll;
}
/*聊天氣泡*/
.my-message-box {
display: flex;
justify-content: flex-end;
align-content: center;
margin: 5px;
}
.other-message-box {
display: flex;
justify-content: flex-start;
align-content: center;
margin: 5px;
}
.message-content {
display: flex;
justify-content: center;
align-content: center;
background-color: #51D15B;
padding:5px 10px;
border-radius: 15px;
color: #fff;
}
.other-message-content{
display: flex;
justify-content: center;
align-content: center;
background-color: #79C2EA;
padding: 5px 10px;
border-radius: 15px;
color: #fff;
}
.message-content span{
padding:20px 0px;
}
.user-chat-img {
width: 50px;
height: 50px;
}
.other-message-content span{
padding: 20px 0px;
}
.message-arrow{
width: 0;
height: 0;
border-width:8px;
border-style: solid;
border-color: transparent transparent transparent #51D15B;
align-self: center;
}
.other-message-arrow{
width: 0;
height: 0;
border-width: 8px;
border-style: solid;
border-color: transparent #79C2EA transparent transparent;
align-self: center;
}
.user-information{
display: flex;
flex-direction: column;
align-content: flex-end;
}
.other-user-information{
display: flex;
flex-direction: column;
align-content: flex-end;
}
.user-chat-name{
color: #333;
font-size: 16px;
text-align: center;
}
/* 聊天輸入框 */
.chat-edit{
margin-top: 5px;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 1px 1px 15px #7B8C99;
overflow: hidden;
}
/* 聊天輸入框輸入?yún)^(qū)域 */
.edit-box{
width: 80%;
height: 100%;
margin: 5px;
border: none;
outline: none;
}
/* 聊天輸入框按鈕 */
.edit-button{
height: 100%;
padding: 5px 15px;
background: #fff;
color: #79C2EA;
outline: none;
border: none;
border-radius: 15px;
cursor: pointer;
font-size: 14px;
font-weight: bold;
}
/* 主體右側(cè) */
.chat-body-right{
height: 100%;
width: 30%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin: 5px;
box-shadow: 1px 1px 15px #7B8C99;
}
.user-name{
margin: 15px;
font-size: 18px;
font-weight: bold;
color: #79C2EA;
}
.user-img{
width: 100px;
height: 100px;
margin: 5px;
}
.online-count{
font-size: 18px;
font-weight: bold;
color: #79C2EA;
}
/* 兼容小屏幕 */
@media screen and (max-width:420px){
.chat-box{
width: 50%;
max-width: 720px;
min-width: 300px;
height: 80%;
min-height: 530px;
max-height: 530px;
}
.chat-body-left{
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
justify-content: space-around;
margin: 5px;
}
.chat-body-right{
display: none;
}
}
index.js
// 獲取url里面的內(nèi)容
var url = decodeURI(location.href).split('?')[1].split('&'); //..數(shù)組第一個(gè)元素為圖片路徑,第二個(gè)元素為用戶名
console.log(url);
// 獲取聊天內(nèi)容框
var chatContent = document.getElementsByClassName('chat-content')[0];
// 獲取聊天輸入框
var editBox = document.getElementsByClassName('edit-box')[0];
// 獲取聊天輸入框發(fā)送按鈕
var editButton = document.getElementsByClassName('edit-button')[0];
// 獲取用戶名欄
var userName = document.getElementsByClassName('user-name')[0];
// 獲取在線人數(shù)欄
var onlineCount = document.getElementsByClassName('online-count')[0];
// 登錄頁(yè)面的名稱(chēng)放在右側(cè)
userName.innerHTML = url[1].split('=')[1];
var userImg = document.getElementsByClassName('user-img')[0];
// 把登錄頁(yè)面的頭像放在右側(cè)
userImg.src = `./img/${url[0].split('=')[1]}`;
var logOut = document.getElementsByClassName('log-out')[0];
// 發(fā)送按鈕綁定點(diǎn)擊事件
editButton.addEventListener('click',sendMessage);
// 登出按鈕綁定點(diǎn)擊事件
logOut.addEventListener('click',closePage);
// 綁定Enter鍵和發(fā)送事件
document.onkeydown = function(event){
var e = event || window.event;
if(e && e.keyCode === 13){
if(editBox.value !== ''){
editButton.click();
}
}
};
// 關(guān)閉頁(yè)面
function closePage(){
var userAgent = navigator.userAgent;
console.log(`userAgent=${userAgent}`);
if(userAgent.indexOf('Firefox') != -1 || userAgent.indexOf("Chrome") != -1){ //..如果是火狐或者谷歌
window.location.href = "about:blank";
}else{
window.opener = null;
window.open("","_self");
window.close();
}
}
// socket部分
var socket = io();
// 當(dāng)接收到消息并且不是本機(jī)時(shí)生成聊天氣泡
socket.on('message',function(information){
console.log('收到消息',information);
if(information.name !== userName.textContent){ // 不是本機(jī)時(shí)
createOtherMessage(information); // 生成聊天氣泡
}
});
// 當(dāng)接收到有人連接進(jìn)來(lái)
socket.on('connected',function(onlinecount){
console.log(`有人登錄,在線人數(shù)為:${onlinecount}`);
onlineCount.innerHTML = 'Online:' + onlinecount;
});
// 當(dāng)接收到有人斷開(kāi)后
socket.on('disconnected',function(onlinecount){
console.log(`有人斷開(kāi)啦:當(dāng)前人數(shù)為:${onlinecount}`);
onlineCount.innerHTML = 'Online:' +onlinecount;
});
// 發(fā)送本機(jī)的消息
function sendMessage(){
if(editBox.value != ''){ //..如果發(fā)送內(nèi)容不為空
var myInformation = {
name :userName.textContent,
chatContent : editBox.value,
img : userImg.src
};
socket.emit('message',myInformation);
createMyMessage(); // 創(chuàng)建本機(jī)聊天氣泡
editBox.value = ''; //..清空文本框
}
}
// 生成本機(jī)的聊天氣泡
function createMyMessage(){
var myMessageBox = document.createElement('div');
myMessageBox.className = 'my-message-box';
var messageContent = document.createElement('div');
messageContent.className = 'message-content';
var text = document.createElement('span');
text.innerHTML = editBox.value;
messageContent.appendChild(text);
myMessageBox.appendChild(messageContent);
var arrow = document.createElement('div');
arrow.className = 'message-arrow';
myMessageBox.appendChild(arrow);
var userInformation = document.createElement('div');
userInformation.className = 'user-information';
var userChatImg = document.createElement('img');
userChatImg.className = 'user-chat-img';
userChatImg.src = userImg.src;
var userChatName = document.createElement('div');
userChatName.className = 'user-chat-name';
userChatName.innerHTML= userName.textContent;
userInformation.appendChild(userChatImg);
userInformation.appendChild(userChatName);
myMessageBox.appendChild(userInformation);
chatContent.appendChild(myMessageBox);
chatContent.scrollTop = chatContent.scrollHeight; // 滾動(dòng)到最新聊天內(nèi)容
}
// 生成其他用戶的聊天氣泡
function createOtherMessage(information) {
var otherMessageBox = document.createElement('div');
otherMessageBox.className = 'other-message-box';
var otherUserInformation = document.createElement('div');
otherUserInformation.className = 'other-user-information';
var userChatImg = document.createElement('img');
userChatImg.className = 'user-chat-img';
userChatImg.src = information.img;
var userChatName = document.createElement('span');
userChatName.className = 'user-chat-name';
userChatName.innerHTML = information.name;
otherUserInformation.appendChild(userChatImg);
otherUserInformation.appendChild(userChatName);
otherMessageBox.appendChild(otherUserInformation);
var otherMessageArrow = document.createElement('div');
otherMessageArrow.className = 'other-message-arrow';
otherMessageBox.appendChild(otherMessageArrow);
var otherMessageContent = document.createElement('div');
otherMessageContent.className = 'other-message-content';
var text = document.createElement('span');
text.innerHTML = information.chatContent;
otherMessageContent.appendChild(text);
otherMessageBox.appendChild(otherMessageContent);
chatContent.appendChild(otherMessageBox);
chatContent.scrollTop = chatContent.scrollHeight;
}
server.js
// 引入必須模棱
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var path = require('path');
// 在線人數(shù)統(tǒng)計(jì)
var onlineCount = 0;
app.use(express.static(__dirname));
// 路徑映射
app.get('/login.html',function(request,response){
response.sendFile('login.html');
});
// 當(dāng)有用戶連接進(jìn)來(lái)時(shí)
io.on('connection',function(socket){
console.log('a user connected');
// 發(fā)送給客戶端在線人數(shù)
io.emit('connected',++onlineCount);
// 當(dāng)有用戶斷開(kāi)
socket.on('disconnect',function(){
console.log('user disconnected');
// 發(fā)送給客戶端人數(shù)
io.emit('disconnected',--onlineCount);
console.log(onlineCount);
});
// 收到了客戶端發(fā)來(lái)的消息
socket.on('message',function(message){
// 給客戶端發(fā)送消息
console.log('服務(wù)器收到的消息為:',message);
io.emit('message',message);
});
});
var server = http.listen(4000,function(){
console.log('Server is running');
});
最后
終端輸入
node server.js
瀏覽器地址欄輸入
http://localhost:4000/login.html



以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- node.js中koa和express的差異對(duì)比
- Node.js中Express框架使用axios同步請(qǐng)求(async+await)實(shí)現(xiàn)方法
- node.js使用express-jwt報(bào)錯(cuò):expressJWT?is?not?a?function解決
- Node.js使用express寫(xiě)接口的具體代碼
- Node.js?express中的身份認(rèn)證的實(shí)現(xiàn)
- 使用Express+Node.js對(duì)mysql進(jìn)行增改查操作?
- node.js三個(gè)步驟實(shí)現(xiàn)一個(gè)服務(wù)器及Express包使用
- Node.js中Express框架的使用教程詳解
- node.js+express留言板功能實(shí)現(xiàn)示例
- node.js使用express-fileupload中間件實(shí)現(xiàn)文件上傳
- Express框架實(shí)現(xiàn)簡(jiǎn)單攔截器功能示例
相關(guān)文章
Node.js編寫(xiě)組件的三種實(shí)現(xiàn)方式
這篇文章主要介紹了Node.js編寫(xiě)組件的三種實(shí)現(xiàn)方式,包括純js實(shí)現(xiàn)、v8 API實(shí)現(xiàn)(同步&異步)、借助swig框架實(shí)現(xiàn),感興趣的小伙伴們可以參考一下2016-02-02
利用node.js啟動(dòng)本地服務(wù)器的操作指南(超詳細(xì))
這篇文章主要介紹了利用node.js啟動(dòng)本地服務(wù)器的操作指南(超詳細(xì)),有很多小伙伴制作網(wǎng)站或者小程序時(shí),需要通過(guò)服務(wù)器來(lái)把前端和后端連接起來(lái),那么我們今天學(xué)習(xí)啟動(dòng)node.js服務(wù)器,文中有詳細(xì)的代碼示例和圖文供大家參考,具有一定的參考價(jià)值,需要的朋友可以參考下2024-05-05
node.js中的path.join方法使用說(shuō)明
這篇文章主要介紹了node.js中的path.join方法使用說(shuō)明,本文介紹了path.join的方法說(shuō)明、語(yǔ)法、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下2014-12-12
深入理解Puppeteer的入門(mén)教程和實(shí)踐
這篇文章主要介紹了深入理解Puppeteer的入門(mén)教程和實(shí)踐,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-03-03
Nodejs 搭建簡(jiǎn)單的Web服務(wù)器詳解及實(shí)例
這篇文章主要介紹了Nodejs 搭建簡(jiǎn)單的Web服務(wù)器詳解及實(shí)例的相關(guān)資料,并附實(shí)例代碼和實(shí)現(xiàn)效果圖,需要的朋友可以參考下2016-11-11
nodejs開(kāi)發(fā)微信小程序?qū)崿F(xiàn)密碼加密
本文給大家分享的是在使用nodejs開(kāi)發(fā)微信小程序的過(guò)程中,實(shí)現(xiàn)密碼加密的示例代碼,非常簡(jiǎn)單,有需要的小伙伴可以參考下2017-07-07

