上面,我们已经创建了一个应用程序,并确定了它的端口。接下来,我们注册的路由,其中,在这种情况下,是没有任何参数的简单GET请求。现在,路由的处理程序仅仅发送一些文本给客户端。最后,当然,在底部,我们运行服务器。初始化应用程序,从控制台执行:
服务器正在运行,所以你应该能够打开http://127.0.0.1:3700/看到:
It works!
现在,不是为了“It works”,我们应该服务于HTML。相对于纯HTML,也是有利的使用模板引擎。Jade是一个很好的选择,它和ExpressJS良好的整合到了一起。这是我在我自己的项目中通常使用的。创建一个目录,名为TPL,并把下面的page.jade文件写成这样:
!!!
html
head
title=
"Real time web chat"
body
.controls
input.field(style=
'width:350px;'
)
input.send(type=
'button'
, value=
'send'
)
Jade的语法不是很复杂,但是,对于一个完整的指南,我建议你参考jade-lang.com。为了使用Jade与ExpressJS,我们需要进行以下设置。
app.set('views', __dirname + '/tpl');
app.set('view engine', "jade");
app.engine('jade', require('jade').__express);
app.get("/", function(req, res){
res.render("page");
});
此代码告知EXPRESS,你的模板文件在哪,并且要使用什么模板引擎。这一切都指定了将处理模板的代码的功能。一切都配置好,我们可以使用response
对象的.render方法
,发送我们的Jade代码给用户。
这一点上,
输出没有什么特别; 无非更多div
元件(具有ID 的content
),这将在作为用于保存聊天消息,两个控制(输入区域和按钮),这我们将用于发送消息。
因为我们将使用前端逻辑外部JavaScript文件,我们需要告知ExpressJS到哪里寻找这些资源。创建一个空目录public
以及在调用.listen方法之前添加如下内容:
app.use(express.static(__dirname + '/public'));
到现在为止还挺好; 我们有成功响应GET请求的服务器。现在,是时候添加Socket.io整合。改变这一行:
app.listen(port);
to:
var io = require('socket.io').listen(app.listen(port));
至此,我们过渡ExpressJS服务器到Socket.io。实际上,我们的实时通讯仍然会发生相同的端口上。
更进一步,我们需要编写会从客户端接收消息的代码,并将其发送给所有的人。每Socket.io应用开始于一个connection
处理程序。我们应该有一个:
io.sockets.on('connection', function (socket) {
socket.emit('message', { message: 'welcome to the chat' });
socket.on('send', function (data) {
io.sockets.emit('message', data);
});
});
该对象socket
,它被传递到您的处理程序,实际上是客户端的Socket。想想它作为您的服务器和用户浏览器之间的连接点。连接成功后,我们发送welcome
消息类型,以及当然,绑定将用作接收器的另一个处理程序。其结果是,客户端应该发出名为send
的消息
,我们将捕获。下面,我们简单地由用户发送到所有其它Socket上的数据转发io.sockets.emit
。
有了上面的代码,我们的后端准备好接收和发送信息到客户端。让我们添加一些前端代码
开发前端
创建chat.js
,并将其放置在内部public
应用程序的目录。粘贴以下代码:
window.onload = function() {
var messages = [];
var socket = io.connect('http://localhost:3700');
var field = document.getElementById("field");
var sendButton = document.getElementById("send");
var content = document.getElementById("content");
socket.on('message', function (data) {
if(data.message) {
messages.push(data.message);
var html = '';
for(var i=0; i<messages.length; i++) {
html += messages[i] + '<br />';
}
content.innerHTML = html;
} else {
console.log("There is a problem:", data);
}
});
sendButton.onclick = function() {
var text = field.value;
socket.emit('send', { message: text });
};
}
我们的逻辑是包裹在一个.onload
处理器只是为了确保所有的标记和外部JavaScript全部加载。在接下来的几行,我们创建了一个数组,将所有的消息,存储在socket
对象,一些快捷方式到我们的DOM元素。再次,类似于后端,我们结合一个功能,这将对Socket活动作出反应。就我们而言,这是一个事件,故名message
。当这样的事件发生时,我们希望接收对象,数据,与属性,message
。该消息添加到我们的存储和更新content
div
。我们还包括了发送消息的逻辑。这很简单,只需用发光的名字的消息,发送。
如果你打开http://localhost:3700,你会遇到一些错误弹出。这是因为我们需要更新page.jade
包含必要的JavaScript文件。
head
title=
"Real time web chat"
script(src=
'/chat.js'
)
script(src=
'/socket.io/socket.io.js'
)
注意到Socket.io管理的递送socket.io.js。你不必担心手动下载该文件。
我们可以再次运行我们的服务器node index.js
控制台和开放的http://localohost:3700。您应该看到欢迎消息。当然,如果你送东西,应该在内容的显示div
。如果你想以确保它正常工作,打开一个新标签(或更好,一个新的浏览器)和加载应用程序。有关Socket.io伟大的事情是,它的作品,即使你停止服务器的NodeJS。前端将继续工作。一旦服务器重新启动后,您的聊天会被fine了。
在当前状态下,我们的聊天是不完美的,需要一些改进。
改进
我们需要做的第一个变化是对消息本身。目前,还不清楚哪些邮件是由谁发送。好事是,我们并不需要更新我们的代码的NodeJS实现这一目标。这是因为服务器只是转发data
对象。因此,我们需要添加一个新的属性那里,后来读它。做更正之前chat.js
,让我们来添加一个新的input
领域,在这里用户可以添加他/她的名字。在page.jade
中,更改controls
div
:
1
2
3
4
5
6
|
.controls
| Name:
input
br
input
input
|
接下来 , code.js:
window.onload = function() {
var messages = [];
var socket = io.connect('http://localhost:3700');
var field = document.getElementById("field");
var sendButton = document.getElementById("send");
var content = document.getElementById("content");
var name = document.getElementById("name");
socket.on('message', function (data) {
if(data.message) {
messages.push(data);
var html = '';
for(var i=0; i<messages.length; i++) {
html += '<b>' + (messages[i].username ? messages[i].username : 'Server') + ': </b>';
html += messages[i].message + '<br />';
}
content.innerHTML = html;
} else {
console.log("There is a problem:", data);
}
});
sendButton.onclick = function() {
if(name.value == "") {
alert("Please type your name!");
} else {
var text = field.value;
socket.emit('send', { message: text, username: name.value });
}
};
}
总结这些变化,我们做了:
- 增加了对用户名的一个新的快捷
input区域
- 更新了消息位的呈现
- 附加了新的
username
属性的对象,其被发送到服务器
如果消息的数量过高,则用户将需要滚动div
:
content.innerHTML = HTML;
content.scrollTop = content.scrollHeight;
请记住,上述方案很可能不会在IE7和下面的工作,不过没关系:IE7已经消逝。但是,如果你想确保支持,随意使用jQuery:
$("#content").scrollTop($("#content")[0].scrollHeight);
如果输入字段在发送消息后清除这也将是不错的:
socket.emit('send', { message: text, username: name.value });
field.value = "";
最后一个无聊的问题是的点击发送每次按钮。带触摸jQuery的,我们可以听当用户按下了Enter
键。
$(document).ready(function() {
$("#field").keyup(function(e) {
if(e.keyCode == 13) {
sendMessage();
}
});
});
函数sendMessage
,可以注册,就像这样:
sendButton.onclick = sendMessage = function() {
...
};
请注意,这不是最好的做法,因为它是注册为一个全球性的功能。但是,对于我们在这里的小测试,它会被fine。