//服务器及页面部分 var express = require('express'), app = express(), server = require('http').createServer(app), io = require('socket.io').listen(server), users=[];//保存所有在线用户的昵称 app.use('https://www.jb51.net/', express.static(__dirname + '/www')); server.listen(80); //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); //向所有连接到服务器的客户端发送当前登陆用户的昵称 }; }); });
需要解释一下的是,在connection事件的回调函数中,socket表示的是当前连接到服务器的那个客户端。所以代码socket.emit('foo')则只有自己收得到这个事件,而socket.broadcast.emit('foo')则表示向除自己外的所有人发送该事件,另外,上面代码中,io表示服务器整个socket连接,所以代码io.sockets.emit('foo')表示所有人都可以收到该事件。
上面代码先判断接收到的昵称是否已经存在在users中,如果存在,则向自己发送一个nickExisted事件,在前端接收到这个事件后我们显示一条信息通知用户。
将下面代码添加到hichat.js的inti方法中。
www/scripts/hichat.js
this.socket.on('nickExisted', function() { document.getElementById('info').textContent = '!nickname is taken, choose another pls'; //显示昵称被占用的提示 });
如果昵称没有被其他用户占用,则将这个昵称压入users数组,同时将其作为一个属性存到当前socket变量中,并且将这个用户在数组中的索引(因为是数组最后一个元素,所以索引就是数组的长度users.length)也作为属性保存到socket中,后面会用到。最后向自己发送一个loginSuccess事件,通知前端登陆成功,前端接收到这个成功消息后将灰色遮罩层移除显示聊天界面。
将下面代码添加到hichat.js的inti方法中。
www/scripts/hichat.js
this.socket.on('loginSuccess', function() { document.title = 'hichat | ' + document.getElementById('nicknameInput').value; document.getElementById('loginWrapper').style.display = 'none';//隐藏遮罩层显聊天界面 document.getElementById('messageInput').focus();//让消息输入框获得焦点 });
在线统计
这里实现显示在线用户数及在聊天主界面中以系统身份显示用户连接离开等信息。
上面server.js中除了loginSuccess事件,后面还有一句代码,通过io.sockets.emit 向所有用户发送了一个system事件,传递了刚登入用户的昵称,所有人接收到这个事件后,会在聊天窗口显示一条系统消息'某某加入了聊天室'。同时考虑到在前端我们无法得知用户是进入还是离开,所以在这个system事件里我们多传递一个数据来表明用户是进入还是离开。
将server.js中login事件更改如下:
server.js
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'); }; });
较之前,多传递了一个login字符串。
同时再添加一个用户离开的事件,这个可能通过socket.io自带的disconnect事件完成,当一个用户断开连接,disconnect事件就会触发。在这个事件中,做两件事情,一是将用户从users数组中删除,一是发送一个system事件通知所有人'某某离开了聊天室'。
将以下代码添加到server.js中connection的回调函数中。
server.js
//断开连接的事件 socket.on('disconnect', function() { //将断开连接的用户从users中删除 users.splice(socket.userIndex, 1); //通知除自己以外的所有人 socket.broadcast.emit('system', socket.nickname, users.length, 'logout'); });
上面代码通过JavaScript数组的splice方法将当前断开连接的用户从users数组中删除,这里我们看到之前保存的用户索引被使用了。同时发送和用户连接时一样的system事件通知所有人'某某离开了',为了让前端知道是离开事件,所以发送了一个'logout'字符串。
下面开始前端的实现,也就是接收system事件。
在hichat.js中,将以下代码添加到init方法中。
www/scripts/hichat.js