2016.4.5_基于nodejs的聊天室【笔记】
1.下载安装nodeJs到一个目录。装好后文件夹下会包括一个node_modules文件夹,一个node.exe文件还有一些其他文件。(懒得重装,可能就是下图选中的那些文件)
每一个chatdemo文件夹都是一个工程,里面包含了js前端、后端文件。
2.server.js文件是服务端js,启动工程就是从它开始。
3.启动工程:
找到nodejs安装目录里的Node.js command prompt,长得和cmd一样。
打开D盘:【d:回车】
打开D盘下chatdemo4文件夹:【cd chatdemo4】
启动js文件:【node server.js】
3.浏览器输入localhost:4000就能看到效果。
4.代码:
server.js
//服务器及页面部分 var express = require('express'), app = express(), server = require('http').createServer(app), io = require('socket.io').listen(server), users=[];//保存所有在线用户的昵称 app.use('/', express.static(__dirname + '/www')); server.listen(4000); //socket部分 io.on('connection', function(socket) { //昵称设置&初始登录 socket.on('login', function(nickname) { var uservalue; var all=''; if (users.indexOf(nickname) > -1) { socket.emit('nickExisted'); } else { socket.userIndex = users.length; socket.nickname = nickname; users.push(nickname); for (var i =0; i<users.length; i++) { uservalue = users[i]; all=all+uservalue+','; } all= all.slice(0,-1); socket.emit('loginSuccess'); io.sockets.emit('system', nickname, users.length, all,'login'); }; }); //断开连接的事件 socket.on('disconnect', function() { var uservalue; var all=''; //将断开连接的用户从users中删除 users.splice(socket.userIndex, 1); for (var i =0; i<users.length; i++) { uservalue = users[i]; all=all+uservalue+','; } all= all.slice(0,-1); //通知除自己以外的所有人 socket.broadcast.emit('system', socket.nickname, users.length,all,'logout'); //io.sockets.emit('system', nickname, users.length, all,'login'); }); //接收新消息 socket.on('postMsg', function(msg,color) { //将消息发送到除自己外的所有用户 socket.broadcast.emit('newMsg', socket.nickname, msg,color); }); //接收用户发来的图片 socket.on('img', function(imgData) { //通过一个newImg事件分发到除自己外的每个用户 socket.broadcast.emit('newImg', socket.nickname, imgData); }); // when the client emits 'typing', we broadcast it to others socket.on('typing', function () { socket.broadcast.emit('typing', { username: socket.nickname }); }); // when the client emits 'stop typing', we broadcast it to others socket.on('stop typing', function () { socket.broadcast.emit('stop typing', { username: socket.nickname }); }); });
package.json
{ "name": "hichat", "description": "a realtime chat web application", "version": "0.4.0", "main": "server.js", "dependencies": { "express": "3.4.x", "socket.io": "0.9.x" }, "engines": { "node": "0.10.x", "npm": "1.2.x" } }
index.html
<!doctype html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="author" content="Wayou"> <meta name="description" content="hichat | a simple chat application built with node.js and websocket"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>hichat</title> <link rel="stylesheet" href="styles/main.css"> <link rel="shortcut icon" href="favicon.ico" type="image/x-icon"> <link rel="icon" href="favicon.ico" type="image/x-icon"> </head> <body onclick=test()> <div class="wrapper"> <div class="banner"> <div id="ul">Welcome to Chat Room (•̀ᴗ•́)و ̑</div> <span id="status"></span> </div> <div id="historyMsg"> </div> <div class="controls" > <div class="items"> <input id="colorStyle" type="color" /> <input id="emoji" class="Btn" type="button" value="emoji" title="emoji" /> <label for="sendImage" class="imageLable"> <input id="imageBtn" class="Btn" type="button" value="image" /> <input id="sendImage" type="file" value="image"/> </label> <input id="clearBtn" class="Btn" type="button" value="clear" title="clear screen" /> </div> <textarea id="messageInput" placeHolder="Enter to Send"></textarea> <div id="emojiWrapper"> </div> </div> </div> <div id="loginWrapper"> <p id="info">connecting to server...</p> <div id="nickWrapper"> <input type="text" placeHolder="" id="nicknameInput" /> </div> </div> <script src="/socket.io/socket.io.js"></script> <script src="scripts/hichat.js"></script> </body> </html>
Hichat.js
window.onload = function() { //初始化程序 var hichat = new HiChat(); hichat.init(); }; var step=0; var _title1=document.title; var _title2='New Message'; var flag=0; for(var i=0;_title2.length<=_title1.length-1;i++) {_title2+='.';} function flash_title() { if(flag==0){ step++; if (step==3) {step=1;} if (step==1) {document.title=_title2;} if (step==2) {document.title=_title1;} setTimeout("flash_title()",500); } } function test() { flag=1; document.title = 'hichat | ' + document.getElementById('nicknameInput').value; } //定义我们的hichat类 var HiChat = function() { this.socket = null; }; //向原型添加业务方法 HiChat.prototype = { init: function() {//此方法初始化程序 var that = this; //建立到服务器的socket连接 this.socket = io.connect(); //监听socket的connect事件,此事件表示连接已经建立 this.socket.on('connect', function() { //连接到服务器后,显示昵称输入框 document.getElementById('info').textContent = 'whats your nickname'; document.getElementById('nickWrapper').style.display = 'block'; document.getElementById('nicknameInput').focus(); }); 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); } else { //否则输入框获得焦点 document.getElementById('nicknameInput').focus(); }; }; }, false); this.socket.on('nickExisted', function() { document.getElementById('info').textContent = 'nickname has been taken, choose another pls'; //显示昵称被占用的提示 }); this.socket.on('loginSuccess', function() { document.title = 'hichat | ' + document.getElementById('nicknameInput').value; document.getElementById('loginWrapper').style.display = 'none';//隐藏遮罩层显聊天界面 document.getElementById('messageInput').focus();//让消息输入框获得焦点 }); this.socket.on('system', function(nickName, userCount, all, type) { var msg = '【' + nickName + '】' + (type == 'login' ? ' Joined' : ' left'); //指定系统消息显示为红色 that._displayNewMsg('system', msg, 'red'); //将在线人数显示到页面顶部 document.getElementById('status').textContent = userCount + (userCount > 1 ? ' users' : ' user') + ' online : ' + all + '.'; }); document.getElementById('messageInput').addEventListener('keyup', function(e) { var messageInput = document.getElementById('messageInput'), msg = messageInput.value, color = document.getElementById('colorStyle').value; flag=0; document.title = 'hichat | ' + document.getElementById('nicknameInput').value; if (e.keyCode == 13 && msg.trim().length != 0) { messageInput.value = ''; that.socket.emit('postMsg', msg, color); that._displayNewMsg('me', msg, color); }; }, false); //接收后台消息 this.socket.on('newMsg', function(user, msg, color) { that._displayNewMsg(user, msg, color); flash_title(); }); document.getElementById('sendImage').addEventListener('change', function() { //检查是否有文件被选中 if (this.files.length != 0) { //获取文件并用FileReader进行读取 var file = this.files[0], reader = new FileReader(); if (!reader) { that._displayNewMsg('system', '!your browser doesn\'t support fileReader', 'red'); this.value = ''; return; }; reader.onload = function(e) { //读取成功,显示到页面并发送到服务器 this.value = ''; that.socket.emit('img', e.target.result); that._displayImage('me', e.target.result); }; reader.readAsDataURL(file); }; }, false); this.socket.on('newImg', function(user,img,color) { that._displayImage(user,img,color); }); this._initialEmoji(); document.getElementById('emoji').addEventListener('click', function(e) { var emojiwrapper = document.getElementById('emojiWrapper'); emojiwrapper.style.display = 'block'; e.stopPropagation(); }, false); document.body.addEventListener('click', function(e) { var emojiwrapper = document.getElementById('emojiWrapper'); if (e.target != emojiwrapper) { emojiwrapper.style.display = 'none'; }; }); document.getElementById('emojiWrapper').addEventListener('click', function(e) { //获取被点击的表情 var target = e.target; if (target.nodeName.toLowerCase() == 'img') { var messageInput = document.getElementById('messageInput'); messageInput.focus(); messageInput.value = messageInput.value + '[emoji:' + target.title + ']'; }; }, false); document.getElementById('clearBtn').addEventListener('click', function(e) { document.getElementById('historyMsg').innerHTML="" ; }, false); }, _displayNewMsg: function(user, msg, color) { var container = document.getElementById('historyMsg'), msgToDisplay = document.createElement('p'), date = new Date().toTimeString().substr(0, 8), //将消息中的表情转换为图片 msg = this._showEmoji(msg); msgToDisplay.style.color = color; if (user == 'system'){ msgToDisplay.style.textAlign = 'center'; msgToDisplay.style.clear = 'both'; user="----System Message : "; msgToDisplay.innerHTML = user + msg + ' at ' + date + ' ----' ; }else if(user == 'me'){ user="Me"; msgToDisplay.style.float = 'right'; msgToDisplay.style.textAlign = 'right'; msgToDisplay.style.width= '600px'; msgToDisplay.style.wordWrap = 'break-word'; msgToDisplay.style.wordBreak = 'normal'; msgToDisplay.innerHTML = '<span class="me">' + user + ' </span>' + '<span class="timespan">(' + date + ') </span>' + '<br>'+ msg; }else{ msgToDisplay.style.float = 'left'; msgToDisplay.style.width= '600px'; msgToDisplay.style.wordWrap = 'break-word'; msgToDisplay.style.wordBreak = 'normal'; msgToDisplay.innerHTML = '<span class="other">' + user + ' </span>' + '<span class="timespan">(' + date + ')</span>' + '<br>'+ msg; } container.appendChild(msgToDisplay); container.scrollTop = container.scrollHeight; }, _displayImage: function(user, imgData, color) { var container = document.getElementById('historyMsg'), msgToDisplay = document.createElement('p'), date = new Date().toTimeString().substr(0, 8); msgToDisplay.style.color = color || '#000'; if (user == 'me') { user="Me"; msgToDisplay.style.float = 'right'; msgToDisplay.style.textAlign = 'right'; msgToDisplay.style.width= '600px'; msgToDisplay.innerHTML = '<span class="me">' + user + ' </span>' + '<span class="timespan">(' + date + '): </span> <br/>' + '<a href="' + imgData + '" target="_blank"><img src="' + imgData + '"/></a>'; }else{ msgToDisplay.innerHTML = user + '<span class="timespan">(' + date + '): </span> <br/>' + '<a href="' + imgData + '" target="_blank"><img src="' + imgData + '"/></a>'; } container.appendChild(msgToDisplay); container.scrollTop = container.scrollHeight; }, _initialEmoji: function() { var emojiContainer = document.getElementById('emojiWrapper'), docFragment = document.createDocumentFragment(); for (var i = 20; i > 0; i--) { var emojiItem = document.createElement('img'); emojiItem.src = '../content/emoji/' + i + '.png'; emojiItem.title = i; docFragment.appendChild(emojiItem); }; emojiContainer.appendChild(docFragment); }, _showEmoji: function(msg) { var match, result = msg, reg = /\[emoji:\d+\]/g, emojiIndex, totalEmojiNum = document.getElementById('emojiWrapper').children.length; while (match = reg.exec(msg)) { emojiIndex = match[0].slice(7, -1); if (emojiIndex > totalEmojiNum) { result = result.replace(match[0], '[X]'); } else { result = result.replace(match[0], '<img class="emoji" src="../content/emoji/' + emojiIndex + '.png" />'); }; }; return result; } };
main.css
html, body { margin: 0; background-color: #efefef; font-family: sans-serif; overflow-y: hidden; } html, input { font: arial,helvetica,sans-serif; } .wrapper { width: 1200px; height: 700px; padding: 5px; margin: 0 auto; background-color: #ddd; } #nicknameInput ,#loginBtn ,#info{ font-size: 250%; text-align:center; } #loginWrapper { position: fixed; top: 0; right: 0; bottom: 0; left: 0; background-color: rgba(5, 5, 5, .9); text-align: center; color: #fff; display: block; padding-top: 200px; } #ul { font-size: 150%; padding: 0 0 0 20px ; } #status { padding: 0 0 0 20px ; color: #A1A1A1; } #nickWrapper { display: none; } .banner { height: 60px; width: 100%; } .banner p { float: right; display: inline-block; } .controls { height: 100px; margin: 5px 0px; position: relative; } #historyMsg { height: 480px; background-color: #fff; overflow: auto; padding: 0 15px 0 15px; margin: 0 15px 0 15px; border-radius: 20px; } .mydiv{ text-align: center; } #historyMsg img { max-width: 30%; } .timespan { color: #ddd; } .me { color: #050505; font-weight: bold; } .other { color: #050505; } .items { height: 30px; overflow:hidden; padding-left: 15px; } #colorStyle { width: 50px; border: none; padding: 0; height: 26px; margin: 0 10px; } .Btn{ width: 60px; height: 26px; vertical-align: middle; margin:0 5px 15px 0; display: inline-block; cursor: pointer; border: 1px solid #BBB; overflow: visible; font: bold 13px arial,helvetica,sans-serif; text-decoration: none; white-space: nowrap; color: #555; background-color: #DDD; background-image: -moz-linear-gradient(center top , #FFF, rgba(255, 255, 255, 0)), url("data:image/png;base64,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"); transition: background-color 0.2s ease-out 0s; background-clip: padding-box; border-radius: 3px; box-shadow: 0px 1px 0px rgba(0, 0, 0, 0.3), 0px 2px 2px -1px rgba(0, 0, 0, 0.5), 0px 1px 0px rgba(255, 255, 255, 0.3) inset; text-shadow: 0px 1px 0px rgba(255, 255, 255, 0.9); } .Btn:hover { background-color: #EEE; color: #555; } /*custom the file input*/ .imageLable { position: relative; } #sendImage { position: absolute; width: 52px; left: 0; opacity: 0; overflow: hidden; } /*end custom file input*/ #messageInput { height: 50px; max-height: 60px; width: 1150px;; padding: 8px; border-radius: 10px; resize: none; margin: 0 15px 0 15px; font: arial,helvetica,sans-serif; } #emojiWrapper { display: none; width: 500px; bottom: 105px; position: absolute; background-color: #aaa; box-shadow: 0 0 10px #555; } #emojiWrapper img { margin: 2px; padding: 2px; width: 25px; height: 25px; } #emojiWrapper img:hover { background-color: blue; } footer { text-align: center; }
参考:
http://www.cnblogs.com/Wayou/p/hichat_built_with_nodejs_socket.html
http://www.tuicool.com/articles/rieI7v
https://www.zybuluo.com/bornkiller/note/6163
http://www.plhwin.com/2014/05/28/nodejs-socketio/