亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

nodejs+express搭建多人聊天室步驟

 更新時(shí)間:2018年02月12日 11:04:03   投稿:laozhang  
本篇文章給大家詳細(xì)講解了nodejs+express搭建一個(gè)簡(jiǎn)易的多人聊天室的詳細(xì)步驟,有興趣的朋友學(xué)習(xí)下。

前言

本文主要是筆者在學(xué)習(xí)node的時(shí)候,作為練手的一個(gè)小項(xiàng)目,花了幾天空余時(shí)間,邊碼邊寫(xiě)教程的一個(gè)過(guò)程。適用于對(duì)node理論知識(shí)看的多,實(shí)戰(zhàn)少的同學(xué),那么現(xiàn)在就讓我們開(kāi)始吧!

準(zhǔn)備工作

新建一個(gè)文件夾 chatroom

在終端輸入以下命令,按照步驟npm(沒(méi)裝過(guò)的去官網(wǎng)安裝下node和npm)會(huì)自動(dòng)給你生成一個(gè)package.json文件

安裝express和socket.io

package.json文件如下:

//package.json
{
 "name": "chatroom",
 "version": "1.0.0",
 "description": "A simple chatroom",
 "main": "index.js",
 "scripts": {
  "test": "echo \"Error: no test specified\" && exit 1"
 },
 "repository": {
  "type": "git",
  "url": "git+https://github.com/ddvdd008/chatroom.git"
 },
 "keywords": [
  "chatroom",
  "nodejs",
  "express"
 ],
 "author": "ddvdd",
 "license": "ISC",
 "bugs": {
  "url": "https://github.com/ddvdd008/chatroom/issues"
 },
 "homepage": "https://github.com/ddvdd008/chatroom#readme"
}

安裝express和socket.io

npm install express --save 
npm install socket.io --save 

package.json自動(dòng)新增依賴(lài)

"dependencies": {
 "express": "^4.16.2",
 "socket.io": "^2.0.4"
}

因?yàn)槲覀兪褂胑xpress框架寫(xiě)后端服務(wù),用socket.io(Socket.io實(shí)際上是WebSocket的父集,Socket.io封裝了WebSocket和輪詢(xún)等方法,他會(huì)根據(jù)情況選擇方法來(lái)進(jìn)行通訊。)來(lái)對(duì)客戶(hù)端和服務(wù)端建立一個(gè)持久鏈接,便于通訊。

到這里準(zhǔn)備工作進(jìn)行的差不多了,下面我們開(kāi)始一步步實(shí)現(xiàn)。

搭建web服務(wù)器

express創(chuàng)建服務(wù)

學(xué)過(guò)node同學(xué)應(yīng)該不陌生,利用http.createServer就能簡(jiǎn)單的創(chuàng)建一個(gè)服務(wù)器,這次我們利用express來(lái)創(chuàng)建服務(wù)。在項(xiàng)目根目錄創(chuàng)建一個(gè)app.js。

/**
* Created by ddvdd on 2018-02-07.
*/
const express = require('express'); 
const app = express();    // 創(chuàng)建express實(shí)例,賦值給app。
const fs = require('fs');   // 這個(gè)是node的文件讀取模塊,用于讀取文件
const path = require('path');  // 這是node的路徑處理模塊,可以格式化路徑

app.listen(3000,()=>{    
 console.log("server running at 127.0.0.1:3000");  // 代表監(jiān)聽(tīng)3000端口,然后執(zhí)行回調(diào)函數(shù)在控制臺(tái)輸出。
});

/**
* app.get(): express中的一個(gè)中間件,用于匹配get請(qǐng)求,說(shuō)的簡(jiǎn)單點(diǎn)就是node處理請(qǐng)求的路由,對(duì)于不同url請(qǐng)求,讓對(duì)應(yīng)的不同app.get()去處理
* '/': 它匹配get請(qǐng)求的根路由 '/'也就是 127.0.0.1:3000/就匹配到它了
* req帶表瀏覽器的請(qǐng)求對(duì)象,res代表服務(wù)器的返回對(duì)象
*/
app.get('/',(req,res)=>{
 res.redirect('/chat.html');  // express的重定向函數(shù)。如果瀏覽器請(qǐng)求了根路由'/',瀏覽器就給他重定向到 '127.0.0.1:3000/chat.html'路由中
});


/**
* 這里匹配到的是/chat.html就是上面重定向到的路徑。
*/
app.get('/chat.html',(req,res)=>{
 fs.readFile(path.join(__dirname,'./public/chat.html'),function(err,data){  //讀取文件,readFile里傳入的是文件路徑和回調(diào)函數(shù),這里用path.join()格式化了路徑。
  if(err){
   console.error("讀取chat.html發(fā)生錯(cuò)誤",err);     //錯(cuò)誤處理
   res.send('4 0 4');           //如果發(fā)生錯(cuò)誤,向?yàn)g覽器返回404
  } else {
   res.end(data);     //這里的data就是回調(diào)函數(shù)的參數(shù),在readFile內(nèi)部已經(jīng)將讀取的數(shù)據(jù)傳遞給了回調(diào)函數(shù)的data變量。
  }         //我們將data傳到瀏覽器,就是把html文件傳給瀏覽器
 })
});

你們看了以后會(huì)說(shuō),這express框架看來(lái)也沒(méi)那么簡(jiǎn)便啊,一個(gè)最簡(jiǎn)單的發(fā)送單頁(yè)面的方法跟node自帶http.createServer沒(méi)太大區(qū)別餓,也挺麻煩的。從目前來(lái)看確實(shí)如此,我這不是為了讓你們?nèi)菀桌斫饴铩?express提供了一個(gè)非常強(qiáng)大的中間件,幫我們托管靜態(tài)資源文件,下面我們就來(lái)實(shí)現(xiàn):

app.use('/',express.static(path.join(__dirname,'./public'))); //一句話就搞定。

代替原來(lái)的:

app.get('/chat.html',(req,res)=>{
 fs.readFile(path.join(__dirname,'./public/chat.html'),function(err,data){  
  if(err){
   console.error("讀取chat.html發(fā)生錯(cuò)誤",err);     
   res.send('4 0 4');           
  } else {
   res.end(data);     
  }         
 })
});

__dirname表示當(dāng)前文件所在的絕對(duì)路徑,所以我們使用path.join將app.js的絕對(duì)路徑和public加起來(lái)就得到了public的絕對(duì)路徑。用path.join是為了避免出現(xiàn) ././public 這種奇怪的路徑,express.static就幫我們托管了public文件夾中的靜態(tài)資源。只要有 127.0.0.1:3000/XXX/AAA 的路徑都會(huì)去public文件夾下找XXX文件夾下的AAA文件然后發(fā)送給瀏覽器。

現(xiàn)在再來(lái)看這段代碼是不是簡(jiǎn)介了很多,具體了解app.use()干了什么的同學(xué)可以去這里

socket.io建立客戶(hù)端和服務(wù)端的鏈接

創(chuàng)建完上面的服務(wù)后,我們需要把socket.io引用進(jìn)來(lái),讓客戶(hù)端和服務(wù)端建立長(zhǎng)久鏈接。我們把a(bǔ)pp.js進(jìn)行如下改造:

/**
* Created by ddvdd on 2018-02-07.
*/
const express = require('express'); 
const app = express();    // 創(chuàng)建express實(shí)例,賦值給app。
const server = require('http').Server(app); 
const io = require('socket.io')(server);  //將socket的監(jiān)聽(tīng)加到app設(shè)置的模塊里。這兩句理解不了的可以去socket.io官網(wǎng)去看
const path = require('path');  // 這是node的路徑處理模塊,可以格式化路徑

server.listen(3000,()=>{    
 console.log("server running at 127.0.0.1:3000");  // 代表監(jiān)聽(tīng)3000端口,然后執(zhí)行回調(diào)函數(shù)在控制臺(tái)輸出。 
}); 
...
...
app.use('/',express.static(path.join(__dirname,'./public')));  //一句話就搞定。 

/*socket*/ 
io.on('connection',(socket)=>{    //監(jiān)聽(tīng)客戶(hù)端的連接事件 
 
}); 

o.on表示監(jiān)聽(tīng)某個(gè)事件,該事件一發(fā)生,就觸發(fā)回調(diào)函數(shù)。'connection‘就是一個(gè)事件名,它已經(jīng)定義好了,只要用戶(hù)連接上就會(huì)觸發(fā)?,F(xiàn)在app.js基本已經(jīng)完成,我們?cè)诟夸泩?zhí)行:

node app.js

>

現(xiàn)在訪問(wèn)http://127.0.0.1:3000/static/chat.html:

哎?啥也沒(méi)有。。。那不廢話!我們都沒(méi)url請(qǐng)求對(duì)應(yīng)的靜態(tài)資源!

添加靜態(tài)html

我們?cè)陧?xiàng)目根目錄創(chuàng)建public文件夾,public文件夾里面新建chat.html文件:

<!DOCTYPE html> 
<html lang="en"> 
<head> 
 <meta charset="UTF-8"> 
 <title>聊天室</title> 
</head> 
<body> 
這是我們的聊天室 
</body> 
</html> 

現(xiàn)在我們刷新下頁(yè)面,你看頁(yè)面出現(xiàn)了:

>

到這里其實(shí)一個(gè)最簡(jiǎn)單的瀏覽器和web服務(wù)器協(xié)作的項(xiàng)目就已經(jīng)完成,后面我們要不斷完善頁(yè)面,給服務(wù)器后端加業(yè)務(wù)功能來(lái)實(shí)現(xiàn)多人聊天室。

基本功能實(shí)現(xiàn)

登陸功能,我們需要一個(gè)用戶(hù)名,(不需要密碼),該用戶(hù)名必須客戶(hù)端服務(wù)器都有存儲(chǔ)。每次傳輸信息基本都需要包括用戶(hù)名,否則不知道是誰(shuí)發(fā)的。

群聊功能,我們需要分辨信息來(lái)己方和對(duì)方

登陸功能實(shí)現(xiàn)

login頁(yè)面重構(gòu)

最基本的登陸界面由一個(gè)用戶(hù)名輸入框和登錄按鈕組成:

//chat.html
<!DOCTYPE html> 
<html lang="en"> 
<head> 
<meta charset="UTF-8"> 
<title>聊天室</title>
<style>
 *{
  margin:0;
  padding:0;
  box-sizing: border-box;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
 }
 .container{
  position: absolute;
  top:0;
  left:0;
  right:0;
  bottom:0;
  background-color: grey;
  padding: 50px;
 }
 .container .title{
  width:300px;
  margin: 0 auto;
  font-size: 30px;
  font-family: 'Franklin Gothic Medium';
  font-weight: bold;
  text-align: center;
  margin-bottom:50px;
 }
 .container .login-wrap{
  width:400px;
  padding: 20px;
  border: 1px solid #000;
  margin: 0 auto;
  text-align: center;
 }
 .login-wrap .user-ipt{
  width:360px;
  text-align: center;
  vertical-align: middle;
 }
 .login-wrap .login-button{
  width:60px;
  height:24px;
  line-height:20px;
  font-size: 14px;
  padding: 2px 0;
  border-radius: 5px;
  margin-top:10px;
 }
</style> 
</head> 
<body> 
 <div class="container">
  <div class="title">歡迎來(lái)到ddvdd聊天室</div>
  <div class="login-wrap">
   <div class="user-ipt">
    <span class="user-name">用戶(hù)名:</span>
    <input id="name" class="name-ipt" type="text" />
   </div>
   <button id="loginbutton" class="login-button">登陸</button>
  </div>
 </div>
</body> 
</html>

簡(jiǎn)單的加點(diǎn)樣式,靜態(tài)頁(yè)面就完成了,我們刷新下頁(yè)面:

login頁(yè)面交互

昨天下午寫(xiě)到一半。。。部門(mén)突然要去團(tuán)建聚會(huì),只能匆匆提交代碼,草草了事。今天一大早來(lái)到公司繼續(xù)給大家碼

廢話不多說(shuō)進(jìn)入正題,登陸這塊交互,當(dāng)用戶(hù)訪問(wèn)服務(wù)器并且成功登陸算一個(gè)在線登陸人數(shù),每登陸一個(gè)用戶(hù),服務(wù)器都會(huì)把用戶(hù)信息存入一個(gè)數(shù)組中,保存在服務(wù)器,這里要注意一點(diǎn),服務(wù)器會(huì)對(duì)用戶(hù)登陸的用戶(hù)名進(jìn)行校驗(yàn),校驗(yàn)結(jié)果會(huì)返回給客戶(hù)端,客戶(hù)端通過(guò)校驗(yàn)結(jié)果,改變當(dāng)前頁(yè)面是否進(jìn)入聊天頁(yè)面。

上面的服務(wù)器和客戶(hù)端交互都是通過(guò)socket.io來(lái)實(shí)現(xiàn)通訊的,前端的業(yè)務(wù)交互我們這里就采用jquery來(lái)實(shí)現(xiàn),在public文件夾下新建js文件夾,下載jquery-3.2.1.min.js、新建main.js。然后對(duì)chat.html引入需要的sdk:

<script src="js/jquery-3.2.1.min.js"></script>
<script src="js/main.js"></script>
//socket.io官網(wǎng)要求這么引入
<script src="/socket.io/socket.io.js"></script>

引入完sdk,我們對(duì)main的js添加登錄功能:

//main.js
/**
* Created by ddvdd on 2018-02-08.
*/
$(function(){
 const url = 'http://127.0.0.1:3000';
 let _username = '';
 let _$inputname = $('#name');
 let _$loginButton = $('#loginbutton');

 let socket = io.connect(url);

 //設(shè)置用戶(hù)名,當(dāng)用戶(hù)登錄的時(shí)候觸發(fā)
 let setUsername = () => {
  
  _username = _$inputname.val().trim(); //得到輸入框中用戶(hù)輸入的用戶(hù)名

  //判斷用戶(hù)名是否存在
  if(_username) {
   socket.emit('login',{username: _username}); //如果用戶(hù)名存在,就代表可以登錄了,我們就觸發(fā)登錄事件,就相當(dāng)于告訴服務(wù)器我們要登錄了
  }
  else{
   alert('請(qǐng)輸入用戶(hù)名!');
  }
 };
 
 
 
 /*前端事件*/
 _$loginButton.on('click',function (event) { //監(jiān)聽(tīng)按鈕的點(diǎn)擊事件,如果點(diǎn)擊,就說(shuō)明用戶(hù)要登錄,就執(zhí)行setUsername函數(shù)
  setUsername();
 });

 /*socket.io部分邏輯*/ 
 socket.on('loginResult',(data)=>{ 
  /** 
  * 如果服務(wù)器返回的用戶(hù)名和剛剛發(fā)送的相同的話,就登錄 
  * 否則說(shuō)明有地方出問(wèn)題了,拒絕登錄 
  */ 
  if(data.code === 0) { 
   // 登陸成功,切換至聊天室頁(yè)面 
  }
  else if(data.code ===1){ 
   alert('用戶(hù)已登錄!'); 
  }
  else{
   alert('登錄失?。?);
  }
 }) 

});
//app.js
/**
* Created by ddvdd on 2018-02-07.
*/
const express = require('express'); 
const app = express();    // 創(chuàng)建express實(shí)例,賦值給app。
const server = require('http').Server(app); 
const io = require('socket.io')(server);  //將socket的監(jiān)聽(tīng)加到app設(shè)置的模塊里。這兩句理解不了的可以去socket.io官網(wǎng)去看
const path = require('path');  // 這是node的路徑處理模塊,可以格式化路徑

const users = [];     //用來(lái)保存所有的用戶(hù)信息 
let usersNum = 0;     //統(tǒng)計(jì)在線登錄人數(shù)

server.listen(3000,()=>{    
 console.log("server running at 127.0.0.1:3000");  // 代表監(jiān)聽(tīng)3000端口,然后執(zhí)行回調(diào)函數(shù)在控制臺(tái)輸出。 
}); 


/**
* app.get(): express中的一個(gè)中間件,用于匹配get請(qǐng)求,說(shuō)的簡(jiǎn)單點(diǎn)就是node處理請(qǐng)求的路由,對(duì)于不同url請(qǐng)求,讓對(duì)應(yīng)的不同app.get()去處理
* '/': 它匹配get請(qǐng)求的根路由 '/'也就是 127.0.0.1:3000/就匹配到它了
* req帶表瀏覽器的請(qǐng)求對(duì)象,res代表服務(wù)器的返回對(duì)象
*/
app.get('/',(req,res)=>{
 res.redirect('/static/chat.html');  // express的重定向函數(shù)。如果瀏覽器請(qǐng)求了根路由'/',瀏覽器就給他重定向到 '127.0.0.1:3000/chat.html'路由中
});

/** 
* __dirname表示當(dāng)前文件所在的絕對(duì)路徑,所以我們使用path.join將app.js的絕對(duì)路徑和public加起來(lái)就得到了public的絕對(duì)路徑。 
* 用path.join是為了避免出現(xiàn) ././public 這種奇怪的路徑 
* express.static就幫我們托管了public文件夾中的靜態(tài)資源。 
* 只要有 127.0.0.1:3000/XXX/AAA 的路徑都會(huì)去public文件夾下找XXX文件夾下的AAA文件然后發(fā)送給瀏覽器。 
*/ 
app.use('/static',express.static(path.join(__dirname,'./public')));  //一句話就搞定。 

/*socket*/ 
io.on('connection',(socket)=>{    //監(jiān)聽(tīng)客戶(hù)端的連接事件 
 
 socket.on('login',(data)=>{ 

  if(checkUserName(data)){
   socket.emit('loginResult',{code:1}); //code=1 用戶(hù)已登錄 
  }
  else{
   //將該用戶(hù)的信息存進(jìn)數(shù)組中 
   users.push({ 
    username: data.username, 
    message: [] 
   }); 
   socket.emit('loginResult',{code:0}); //code=0 用戶(hù)登錄成功
   usersNum = users.length; 
   console.log(`用戶(hù)${data.username}登錄成功,進(jìn)入ddvdd聊天室,當(dāng)前在線登錄人數(shù):${usersNum}`); 
  }
  
 }); 

 //斷開(kāi)連接后做的事情 
 socket.on('disconnect',()=>{   //注意,該事件不需要自定義觸發(fā)器,系統(tǒng)會(huì)自動(dòng)調(diào)用 
  usersNum = users.length; 
  console.log(`當(dāng)前在線登錄人數(shù):${usersNum}`); 
 }); 
}); 
//校驗(yàn)用戶(hù)是否已經(jīng)登錄
const checkUserName = (data) => {
 let isExist = false;
 users.map((user) => {
  if(user.username === data.username){
   isExist = true;
  }
 });
 return isExist;
}

上面代碼大家需要了解以下幾點(diǎn):

  1. socket.on 表示監(jiān)聽(tīng)事件,后面接一個(gè)回調(diào)函數(shù)用來(lái)接收emit發(fā)出事件傳遞過(guò)來(lái)的對(duì)象。
  2. socket.emit 用來(lái)觸發(fā)事件,傳遞對(duì)象給on監(jiān)聽(tīng)事件。
  3. 我們socket連接之后的監(jiān)聽(tīng)觸發(fā)事件都要寫(xiě)在io.on('connection')的回調(diào)里面,因?yàn)檫@些事件都是連接之后發(fā)生的,就算是斷開(kāi)連接的事件 disconnect 也是在連接事件中發(fā)生的,沒(méi)有正在連接的狀態(tài),哪來(lái)的斷開(kāi)連接呢?
  4. 理解雖然服務(wù)器端只有app.js一個(gè)文件,但是不同的客戶(hù)端連接后信息是不同的,所以我們必須要將一些公用的信息,比如說(shuō),儲(chǔ)存所有登錄用戶(hù)的數(shù)組,所有用戶(hù)發(fā)送的所有信息存儲(chǔ)在外部,一定不能存儲(chǔ)在connecion里

效果展示:

群聊功能實(shí)現(xiàn)

寫(xiě)完簡(jiǎn)單的登錄功能,現(xiàn)在我們來(lái)寫(xiě)這項(xiàng)目最重要的功能群聊。首先我們先來(lái)處理下頁(yè)面,因?yàn)楣δ芎?jiǎn)單,所以不單獨(dú)建立html來(lái)顯示聊天室,就直接寫(xiě)在login頁(yè)面,通過(guò)class名稱(chēng)的變化來(lái)切換登錄后,聊天室的顯示。

聊天室頁(yè)面重構(gòu)

下面我們對(duì)chat.html進(jìn)行整改:

<!DOCTYPE html> 
<html lang="en"> 
<head> 
 <meta charset="UTF-8"> 
 <title>聊天室</title>
 <script src="js/jquery-3.2.1.min.js"></script> 
 <script src="js/main.js"></script> 
 <script src="/socket.io/socket.io.js"></script> 
 <style>
  *{
   margin:0;
   padding:0;
   box-sizing: border-box;
   -webkit-box-sizing: border-box;
   -moz-box-sizing: border-box;
  }
  .container{
   position: absolute;
   top:0;
   left:0;
   right:0;
   bottom:0;
   background-color: darkgrey;
   padding: 50px;
   overflow-y: scroll;
  }
  .container .title{
   margin: 0 auto;
   font-size: 30px;
   font-family: 'Franklin Gothic Medium';
   font-weight: bold;
   text-align: center;
   margin-bottom:20px;
  }
  .container .login-wrap{
   width:400px;
   padding: 20px;
   border: 1px solid #000;
   margin: 0 auto;
   text-align: center;
  }
  .login-wrap .user-ipt{
   width:360px;
   text-align: center;
   vertical-align: middle;
  }
  .login-wrap .login-button{
  width:60px;
  height:24px;
  line-height:20px;
  font-size: 14px;
  padding: 2px 0;
  border-radius: 5px;
  margin-top:10px;
  }
  .chat-wrap .chat-content{
   width:100%;
   height:600px;
   background-color: whitesmoke;
   padding:10px;
  }
  .chat-wrap .send-wrap{
   margin-top: 20px;
  }
  .message-ipt{
   width: 200px;
   height: 100px;
   padding: 0 5px;
   vertical-align: bottom;
  }
  .chat-content p{
   display: block;
   margin-bottom: 10px;
  }
  .chat-content p .msg{
   display: inline-block;
   padding: 8px 11px;
   border-radius:6px;
  }
  .chat-content .self-message .msg{
   background-color:#d0e7ff;
   border: 1px solid #c9dfff;
  }
  .chat-content .other-message .msg{
   background-color:white;
   border: 1px solid #eee;
  }
  .chat-content .self-message{
   text-align:right;
  }
  .chat-content .other-message{
   text-align-last:left;
  }
 </style> 
</head> 
<body> 
 <div class="container">
  <div id="loginbox" class="login-wrap">
   <div class="title">登錄</div>
   <div class="user-ipt">
    <span class="user-name">用戶(hù)名:</span>
    <input id="name" class="name-ipt" type="text" />
   </div>
   <button id="loginbutton" class="login-button">登錄</button>
  </div>
  <div id="chatbox" class="chat-wrap" style="display:none">
   <div id="content" class="chat-content">
    <!-- 聊天內(nèi)容 -->
   </div>
   <div class="send-wrap">
    <textarea rows="3" cols="20" id="chatmessage" class="message-ipt" type="textarea" placeholder="請(qǐng)輸入要發(fā)送的信息內(nèi)容"></textarea>
   </div>
  </div>
 </div>
</body> 
</html> 

新增chatbox容器來(lái)作為聊天室,里面有一個(gè)群聊的聊天框,和一個(gè)發(fā)送消息的文本框。通過(guò)上面loginResult回調(diào),對(duì)loginbox進(jìn)行隱藏,顯示chatbox:

//顯示聊天室界面
let showChatRoom = () => {
 /** 
  * 1.隱藏登錄框,取消它綁定的事件 
  * 2.顯示聊天界面 
  */ 
 $('#loginbox').hide('slow');
 _$loginButton.off('click');
 /** 
 * 顯示聊天界面,并顯示一行文字,歡迎用戶(hù) 
 */
 $(`<div class="title">歡迎${_username}來(lái)到ddvdd聊天室</div>`).insertBefore($("#content")); 
 $("#chatbox").show('slow');
}

消息事件發(fā)送監(jiān)聽(tīng)機(jī)制

聊天一定是客戶(hù)端觸發(fā)的,所以發(fā)送信息是客戶(hù)端觸發(fā),服務(wù)器監(jiān)聽(tīng)。

服務(wù)器監(jiān)聽(tīng)到發(fā)送信息的事件后會(huì)存儲(chǔ)信息,然后觸發(fā)發(fā)送信息成功事件廣播給所有客戶(hù)端,將信息傳給所有客戶(hù)端。

發(fā)送消息sendMessage事件

//main.js
//發(fā)送消息
let sendMessage = function () { 
 /** 
  * 得到輸入框的聊天信息,如果不為空,就觸發(fā)sendMessage 
  * 將信息和用戶(hù)名發(fā)送過(guò)去 
  */ 
 let _message = _$chattextarea.val(); 
 
 if(_message) { 
  socket.emit('sendMessage',{username: _username, message: _message}); 
 }
 else{
  alert('請(qǐng)輸入發(fā)送消息!');
 } 
}; 
...
/*聊天事件*/ 
_$chattextarea.on('keyup',function (event) { 
 if(event.keyCode === 13) { 
  sendMessage(); 
  _$chattextarea.val(''); 
 } 
});

服務(wù)器端監(jiān)聽(tīng)sendMessage事件

//app.js
/** 
 * 監(jiān)聽(tīng)sendMessage,我們得到客戶(hù)端傳過(guò)來(lái)的data里的message,并存起來(lái)。 
 */ 
socket.on('sendMessage',(data)=>{ 
 for(let _user of users) { 
  if(_user.username === data.username) { 
   _user.message.push(data.message); 
   //信息存儲(chǔ)之后觸發(fā)receiveMessage將信息發(fā)給所有瀏覽器-廣播事件 
   io.emit('receiveMessage',data); 
   break; 
  } 
 } 
}); 

我們是遍歷服務(wù)器端的用戶(hù)數(shù)組,找到該用戶(hù),將發(fā)送的信息存起來(lái),然后觸發(fā)receiveMessage事件廣播到所有瀏覽器,sendMessage是寫(xiě)在connection里,login之外的,為什么這么做大家一定要理解,發(fā)送消息是連接時(shí)候做的事情,而不是登錄時(shí)做的事情。

注意的是,我使用的是io.emit,他是真正的廣播到所有瀏覽器,socket.broadcast.emit則不會(huì)廣播到自己的瀏覽器。

客戶(hù)端監(jiān)聽(tīng)receiveMessage事件

//main.js
socket.on('receiveMessage',(data)=>{ 
 /** 
  * 
  * 監(jiān)聽(tīng)服務(wù)器廣播的消息
  */ 
 showMessage(data);
}) 
//顯示消息
let showMessage = function (data) { 
 //先判斷這個(gè)消息是不是自己發(fā)出的,然后再以不同的樣式顯示 
 if(data.username === _username){ 
  $("#content").append(`<p class='self-message'><span class='msg'>${data.message}</span><span class='name'> :${data.username}</span></p>`); 
 }else { 
  $("#content").append(`<p class='other-message'><span class='name'>${data.username}: </span><span class='msg'>${data.message}</span></p>`); 
 } 
}; 

寫(xiě)到這邊,我們的聊天室基本功能已經(jīng)完成了,來(lái)看看效果吧!打開(kāi)三個(gè)瀏覽器,分別登錄老大、老二、老三,發(fā)一句“大噶好~,我是渣渣輝!”。

源碼地址:https://github.com/ddvdd008/chatroom

相關(guān)文章

  • 使用Nodejs編寫(xiě)一個(gè)腳本實(shí)現(xiàn)markdown轉(zhuǎn)pdf功能

    使用Nodejs編寫(xiě)一個(gè)腳本實(shí)現(xiàn)markdown轉(zhuǎn)pdf功能

    Markdown?是一種輕量級(jí)的標(biāo)記語(yǔ)言,非常適合用來(lái)寫(xiě)作和記錄,將?Markdown?轉(zhuǎn)換為?PDF?可以讓文檔在格式和樣式上更加統(tǒng)一,也方便在不同設(shè)備和平臺(tái)上查看和打印,在接下來(lái)的內(nèi)容中我們將講解如何使用?NodeJs?編寫(xiě)一個(gè)?Markdown?轉(zhuǎn)?PDF?的腳本來(lái)實(shí)現(xiàn)我們這個(gè)想要的功能
    2024-05-05
  • node指定內(nèi)存上限簡(jiǎn)單代碼實(shí)例

    node指定內(nèi)存上限簡(jiǎn)單代碼實(shí)例

    NodeJS啟動(dòng)的應(yīng)用,內(nèi)存使用是有上限的,下面這篇文章主要給大家介紹了關(guān)于node指定內(nèi)存上限的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11
  • node.js中的fs.fsync方法使用說(shuō)明

    node.js中的fs.fsync方法使用說(shuō)明

    這篇文章主要介紹了node.js中的fs.fsync方法使用說(shuō)明,本文介紹了fs.fsync的方法說(shuō)明、語(yǔ)法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下
    2014-12-12
  • node.js使用redis儲(chǔ)存session的方法

    node.js使用redis儲(chǔ)存session的方法

    這篇文章主要介紹了node.js使用redis儲(chǔ)存session的方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-09-09
  • 使用node.js半年來(lái)總結(jié)的 10 條經(jīng)驗(yàn)

    使用node.js半年來(lái)總結(jié)的 10 條經(jīng)驗(yàn)

    從3月初來(lái)到帝都某創(chuàng)業(yè)公司的服務(wù)器團(tuán)隊(duì)實(shí)習(xí),到現(xiàn)在已接近半年的時(shí)間。PS: 已轉(zhuǎn)正,服務(wù)器端用的 Node。
    2014-08-08
  • 如何在node的express中使用socket.io

    如何在node的express中使用socket.io

    這篇文章主要介紹了如何在node的express中使用socket.io,需要的朋友可以參考下
    2014-12-12
  • 如何用nodejs搭建代理服務(wù)器

    如何用nodejs搭建代理服務(wù)器

    這篇文章主要介紹了如何用nodejs搭建代理服務(wù)器,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Nodejs使用exceljs實(shí)現(xiàn)excel導(dǎo)入導(dǎo)出

    Nodejs使用exceljs實(shí)現(xiàn)excel導(dǎo)入導(dǎo)出

    在日常開(kāi)發(fā)中,我們常需在后臺(tái)管理系統(tǒng)中實(shí)現(xiàn)數(shù)據(jù)的導(dǎo)入與導(dǎo)出功能,以便與?Excel?文件進(jìn)行交互,本文將使用使用exceljs實(shí)現(xiàn)excel導(dǎo)入導(dǎo)出功能,需要的可以參考下
    2024-03-03
  • Node.js中利用js-xlsx處理xlsx文件的實(shí)現(xiàn)

    Node.js中利用js-xlsx處理xlsx文件的實(shí)現(xiàn)

    js-xlsx庫(kù)是目前Github上star數(shù)量最多的處理Excel的庫(kù),本文介紹用 Node.js中的js-xls庫(kù)來(lái)處理Excel文件,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-10-10
  • node封裝一個(gè)控制臺(tái)進(jìn)度條插件???????詳情

    node封裝一個(gè)控制臺(tái)進(jìn)度條插件???????詳情

    這篇文章主要介紹了node封裝一個(gè)控制臺(tái)進(jìn)度條插件???????詳情,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-08-08

最新評(píng)論