node+express+socket.io打造一個簡單羣聊天室

下圖爲效果圖:

Node相關

首先,咱們要配置node環境。這個能夠查看一個node的安裝教程,http://www.runoob.com/nodejs/nodejs-tutorial.html點擊這個能夠查看怎麼安裝node配置環境。javascript

配置好node環境之後在咱們新建的項目裏面咱們會有以下文件:html

而後咱們就能夠開始建立一個簡單的HTTP服務器啦。前端

相似下面很是簡單的代碼,它建立了一個HTTP服務器並監聽系統的80端口。java

//node server examplenode

//引入http模塊
var http = require('http'),
    //建立一個服務器
    server = http.createServer(function(req, res) {
        res.writeHead(200, {
            'Content-Type': 'text/plain'
        });
        res.write('hello world!');
        res.end();
    });
//監聽80端口
server.listen(80);
console.log('server started')

將其保存爲一個js文件好比server.js,而後從命令行運行node server或者node server.js,服務器即可啓動了,此刻咱們能夠在瀏覽器地址欄輸入localhost進行訪問,也能夠輸入本機IP127.0.0.1,都不用加端口,由於咱們服務器監聽的是默認的80端口。
固然,若是你機子上面80端口被其餘程序佔用了,能夠選擇其餘端口好比8080,這樣訪問的時候須要顯示地加上端口號localhost:8080。

 

Express

首先經過npm進行安裝express

  • 在咱們的項目文件夾下打開命令行(tip: 按住Shift同時右擊,能夠在右鍵菜單中找到'今後處打開命令行'選項)
  • 在命令行中輸入 npm install express 回車進行安裝
  • 而後在server.js中經過require('express')將其引入到項目中進行使用

express是node.js中管理路由響應請求的模塊,根據請求的URL返回相應的HTML頁面。這裏咱們使用一個事先寫好的靜態頁面返回給客戶端,只需使用express指定要返回的頁面的路徑便可。若是不用這個包,咱們須要將HTML代碼與後臺JavaScript代碼寫在一塊兒進行請求的響應,不太方便。npm

//返回一個簡單的HTML內容後端

server = http.createServer(function(req, res) {
    res.writeHead(200, {
        'Content-Type': 'text/html' //將返回類型由text/plain改成text/html
    });
    res.write('<h1>hello world!</h1>'); //返回HTML標籤
    res.end();
});

 在存放上一步建立的server.js文件的地方,咱們新建一個文件夾名字爲www用來存放咱們的網頁文件,包括圖片以及前端的js文件等。假設已經在www文件夾下寫好了一個index.html文件(將在下一步介紹,這一步你能夠放一個空的HTML文件),則能夠經過如下方式使用express將該頁面返回到瀏覽器。能夠看到較最開始,咱們的服務器代碼簡潔了很多。數組

//使用express模塊返回靜態頁面瀏覽器

var express = require('express'), //引入express模塊
    app = express(),
    server = require('http').createServer(app);
app.use('/', express.static(__dirname + '/www')); //指定靜態HTML文件的位置
server.listen(80);

socket.io

Node.js中使用socket的一個包。使用它能夠很方便地創建服務器到客戶端的sockets鏈接,發送事件與接收特定事件。

一樣經過npm進行安裝 npm install socket.io 。安裝後在node_modules文件夾下新生成了一個socket.io文件夾,其中咱們能夠找到一個socket.io.js文件。將它引入到HTML頁面,這樣咱們就能夠在前端使用socket.io與服務器進行通訊了。

<script src="/socket.io/socket.io.js"></script>

同時服務器端的server.js裏跟使用express同樣,也要經過require('socket.io')將其引入到項目中,這樣就能夠在服務器端使用socket.io了。

使用socket.io,其先後端句法是一致的,即經過socket.emit()來激發一個事件,經過socket.on()來偵聽和處理對應事件。這兩個事件經過傳遞的參數進行通訊。具體工做模式能夠看下面這個示例。

好比咱們在index.html裏面有以下JavaScript代碼(假設你已經在頁面放了一個ID爲sendBtn的按鈕):

<script type="text/javascript">
	var socket=io.connect(),//與服務器進行鏈接
		button=document.getElementById('sendBtn');
	button.onclick=function(){
		socket.emit('foo', 'hello');//發送一個名爲foo的事件,而且傳遞一個字符串數據‘hello’
	}
</script>

上述代碼首先創建與服務器的鏈接,而後獲得一個socket實例。以後若是頁面上面一個ID爲sendBtn的按鈕被點擊的話,咱們就經過這個socket實例發起一個名爲foo的事件,同時傳遞一個hello字符串信息到服務器。

與此同時,咱們須要在服務器端寫相應的代碼來處理這個foo事件並接收傳遞來的數據。

爲此,咱們在server.js中能夠這樣寫:

//服務器及頁面響應部分
var express = require('express'),
    app = express(),
    server = require('http').createServer(app),
    io = require('socket.io').listen(server); //引入socket.io模塊並綁定到服務器
app.use('/', express.static(__dirname + '/www'));
server.listen(80);

//socket部分
io.on('connection', function(socket) {
    //接收並處理客戶端發送的foo事件
    socket.on('foo', function(data) {
        //將消息輸出到控制檯
        console.log(data);
    })
});
如今Ctrl+C關閉以前啓動的服務器,再次輸入node server啓動服務器運行新代碼查看效果,一切正常的話你會在點擊了頁面的按扭後,在命令行窗口裏看到輸出的'hello'字符串。

基本頁面

<div class="live-box-right">
<div class="live-chat">
<div class="chat-top">
<span class="chat-tit">聊天室</span>
<i class="chat-all"><img src="img/footballLive/ren_icon.png"/ ><span id="status"></span></i>
</div>
<div class="chat-con" id="message" >
<div class="message" id="historyMsg">
</div>
</div>
<textarea id="messageInput" placeHolder="請輸入文字" class="chatnow" maxlength="80"></textarea>
<input id="sendBtn" type="button" value="發送" class="sendBtn">
</div>
</div>
</div>    //聊天頁面模塊

<div id="loginWrapper">
<p id="info">正在鏈接服務器...</p>
<div id="nickWrapper">
<input type="text" placeHolder="暱稱" id="nicknameInput" />
<input type="button" value="OK" id="loginBtn" />
</div>
</div>       //這裏是登錄的模塊

這個是聊天的基本的頁面結構是這樣的 樣式的話本身寫我就不貼出來

下面開始寫一些基本的前端js開始實現鏈接功能。

定義一個全局變量用於咱們整個程序的開發,同時使用window.onload在頁面準備好以後實例化項目,調用其init方法運行咱們的程序。

window.onload = function() {
//實例並初始化咱們的程序
var hichat = new HiChat();
hichat.init();
};

//定義咱們的類
var HiChat = function() {
this.socket = null;
};

 

//向原型添加業務方法
HiChat.prototype = {
init: function() { //此方法初始化程序
var that = this;
//創建到服務器的socket鏈接
this.socket = io.connect("http://127.0.1.111:8088");
//監聽socket的connect事件,此事件表示鏈接已經創建
this.socket.on('connect', function() {
//鏈接到服務器後,顯示暱稱輸入框
document.getElementById('info').textContent = '請輸入你的暱稱';
document.getElementById('nickWrapper').style.display = 'block';
document.getElementById('nicknameInput').focus();
});

 上面的代碼定義了整個程序須要使用的類HiChat,以後咱們處理消息顯示消息等全部業務邏輯均寫在這個類裏面。

首先定義了一個程序的初始化方法,這裏面初始化socket,監聽鏈接事件,一旦鏈接到服務器,便顯示暱稱輸入框。當用戶輸入暱稱後,即可以在服務器後臺接收到而後進行下一步的處理了。

設置暱稱

//暱稱設置的肯定按鈕
document.getElementById('loginBtn').addEventListener('click', function() {
var nickName = document.getElementById('nicknameInput').value;
//檢查暱稱輸入框是否爲空
if(nickName.trim().length != 0) {
//不爲空,則發起一個login事件並將輸入的暱稱發送到服務器
that.socket.emit('login', nickName);
} else {
//不然輸入框得到焦點
document.getElementById('nicknameInput').focus();
};
}, false);

 server.js文件寫:

var express = require('express'), //引入express模塊
app = express(),
server = require('http').createServer(app);
io = require('socket.io').listen(server); //引入socket.io模塊並綁定到服務器
users=[];//保存全部在線用戶的暱稱
app.use('/', express.static(__dirname + 'footballLive.html')); //指定靜態HTML文件的位置
server.listen(8088);
console.log('server started');

//socket部分
io.on('connection', function(socket) {
//暱稱設置
socket.on('login', function(nickname) {
if (users.indexOf(nickname) > -1) {
socket.emit('nickExisted');
} else {
socket.userIndex = users.length;
socket.nickname = nickname;
users.push(nickname);
socket.emit('loginSuccess');
io.sockets.emit('system', nickname, users.length, 'login');     //向全部鏈接到服務器的客戶端發送當前登錄用戶的暱稱

};

});

上面代碼先判斷接收到的暱稱是否已經存在在users中,若是存在,則向本身發送一個nickExisted事件,在前端接收到這個事件後咱們顯示一條信息通知用戶。

this.socket.on('nickExisted', function() {
document.getElementById('info').textContent = '!nickname is taken, choose another pls'; //顯示暱稱被佔用的提示
});

若是暱稱沒有被其餘用戶佔用,則將這個暱稱壓入users數組,同時將其做爲一個屬性存到當前socket變量中,而且將這個用戶在數組中的索引(由於是數組最後一個元素,因此索引就是數組的長度users.length)也做爲屬性保存到socket中,後面會用到。最後向本身發送一個loginSuccess事件,通知前端登錄成功,前端接收到這個成功消息後將灰色遮罩層移除顯示聊天界面。

this.socket.on('loginSuccess', function() {
document.getElementById('loginWrapper').style.display = 'none'; //隱藏遮罩層顯聊天界面
document.getElementById('messageInput').focus(); //讓消息輸入框得到焦點
});

在線統計

這裏實現顯示在線用戶數及在聊天主界面中以系統身份顯示用戶鏈接離開等信息

this.socket.on('system', function(nickName, userCount, type) {
//判斷用戶是鏈接仍是離開以顯示不一樣的信息
var msg = nickName + (type == 'login' ? '進入聊天室' : '離開');
var p = document.createElement('p');
p.textContent = msg;
document.getElementById('historyMsg').appendChild(p);
//將在線人數顯示到頁面頂部
document.getElementById('status').textContent = userCount + (userCount > 1 ? '' : '');
});

發送消息

用戶鏈接以及斷開咱們須要顯示系統消息,用戶還要頻繁的發送聊天消息,因此能夠考慮將消息顯示到頁面這個功能單獨寫一個函數方便咱們調用。爲此咱們向HiChat類中添加一個_displayNewMsg的方法,它接收要顯示的消息,消息來自誰。

function _displayNewMsg(user, msg) {
var container = document.getElementById('historyMsg'),
content = document.getElementById('message'),
msgToDisplay = document.createElement('p'),
date = new Date().toTimeString().substr(0, 8);
//msgToDisplay.style.color = color || '#000';
msgToDisplay.innerHTML = '<span class="lvon">Lv1</span>' + '<span class="c-blue">' + user + '</span>' + '<span class="timespan">(' + date + '): </span>' + msg;
container.appendChild(msgToDisplay);
container.scrollTop = container.scrollHeight;
content.scrollTop = content.scrollHeight;
}

有了這個顯示消息的方法後,下面就開始實現用戶之間的聊天功能了。

作法也很簡單,若是你掌握了上面所描述的emit發送事件,on接收事件,那麼用戶聊天消息的發送接收也就輕車熟路了。

首先爲頁面的發送按鈕寫一個click事件處理程序,咱們經過addEventListner來監聽這個click事件,當用戶點擊發送的時候,先檢查輸入框是否爲空,若是不爲空,則向服務器發送postMsg事件,將用戶輸入的聊天文本發送到服務器,由服務器接收並分發到除本身外的全部用戶。

將如下代碼添加到hichat.js的inti方法中。

document.getElementById('sendBtn').addEventListener('click', function() {
var messageInput = document.getElementById('messageInput'),
msg = messageInput.value;
messageInput.value = '';
messageInput.focus();
if (msg.trim().length != 0) {
that.socket.emit('postMsg', msg); //把消息發送到服務器
_displayNewMsg('我', msg); //把本身的消息顯示到本身的窗口中
};
}, false);

 在server.js中添加代碼以接收postMsg事件。

io.on('connection', function(socket) {
    //其餘代碼。。。

    //接收新消息
    socket.on('postMsg', function(msg) {
        //將消息發送到除本身外的全部用戶
        socket.broadcast.emit('newMsg', socket.nickname, msg);
    });
});
 而後在客戶端接收服務器發送的newMsg事件,並將聊天消息顯示到頁面。
this.socket.on('newMsg', function(user, msg) {
    that._displayNewMsg(user, msg);
});
運行程序,如今能夠發送聊天消息了。

按鍵操做

將如下代碼添加到hichat.js的inti方法中,這樣在輸入暱稱後,按回車鍵就能夠登錄,進入聊天界面後,回車鍵能夠發送消息。

//按回車鍵發送消息
document.getElementById('nicknameInput').addEventListener('keyup', function(e) {
if (e.keyCode == 13) {
var nickName = document.getElementById('nicknameInput').value;
if (nickName.trim().length != 0) {
that.socket.emit('login', nickName);
};
};
}, false);

document.getElementById('messageInput').addEventListener('keyup', function(e) {
var messageInput = document.getElementById('messageInput'),
msg = messageInput.value;
//color = document.getElementById('colorStyle').value;
if (e.keyCode == 13 && msg.trim().length != 0) {
messageInput.value = '';
that.socket.emit('postMsg', msg);
_displayNewMsg('我', msg);
};
}, false);

一個簡單的聊天室就到這裏了。

相關文章
相關標籤/搜索