當前位置:
首頁 > 知識 > 《基於Node.js實現簡易聊天室系列之詳細設計》

《基於Node.js實現簡易聊天室系列之詳細設計》

一個完整的項目基本分為三個部分:前端、後台和資料庫。依照軟體工程的理論知識,應該依次按照以下幾個步驟:需求分析、概要設計、詳細設計、編碼、測試等。由於缺乏相關知識的儲備,導致這個Demo系列的文章層次不是很清楚,索性這一章將所有的過程(前後端以及資料庫)做一個介紹,下一章寫完總結就OK了吧。

(1)前端部分

涉及到的技術:html、css、bootstrap、jquery、jquery UI

登錄/註冊界面使用的是bootstrap響應式布局,即支持不同尺寸的客戶端,以此提高用戶的體驗。在這之前我以為聊天室比較適合做成SPA(單頁應用),想採取backbone,但是結合畢設的主題是基於Node.js,如果採用backbone,路由功能就有兩種選擇,backbone和Node.js都有著豐富的路由API,由於之前沒有用Node.js做過相關項目,所以就放棄了backbone。Demo通過改變css中display的屬性來控制div的顯示與隱藏。

頁面:

1

2
3
4
5
6

12

13

14

15

16

17

Or

18

19

20

21
22

28

29

30

31

32

33

135

136

137
138
139
140
141

View Code

js:

1 $(function {
2 var CookieObj = {}, socket = io, headInfo = "群聊 (";;
3 window.onbeforeunload = function (e) {
4 if (document.cookie) return false;
5 }
6 render;
7 /*
8 *登錄
9 */
10 var onLogin = function (e) {
11 var xhr;
12 if (!$("#username").val || !$("#userpassword").val) return;
13 xhr = $.ajax({
14 url: "/login",
15 type: "POST",
16 dataType: "json",
17 data: {
18 name: $("#username").val,
19 password: $("#userpassword").val
20 }
21 })
22 .done(function (data, textStatus, jqXHR) {
23 if (data.value === "Y") {
24 render;
25 } else {
26 $("#SignInErr").html(data.msg);
27 }
28 })
29 .fail(function (jqXHR, textStatus, errorThrown) {
30 $("#SignInErr").html("Error occured! Please try again.");
31 });
32 };
33 /*
34 *註冊
35 */
36 var onSignup = function (e) {
37 var xhr;
38 if (!$("#upName").val || !$("#upPassword").val) return;
39 xhr = $.ajax({
40 url: "/signup",
41 type: "POST",
42 dataType: "json",
43 data: {
44 name: $("#upName").val,
45 password: $("#upPassword").val
46 }
47 })
48 .done(function (data, textStatus, jqXHR) {
49 if (data.value === "Y") {
50 $("#SignUpErr").html(data.msg || "Login now with these credentials.");
51 } else {
52 $("#SignUpErr").html(data.msg || "Invalid username");
53 }
54 })
55 .fail(function (jqXHR, textStatus, errorThrown) {
56 $("#SignUpErr").html("Error occured! Please try again.");
57 });
58 };
59
60 var onMsgSubmit = function {
61 var str = $("#msg").val;
62 var sendMsg = replace_em(str);
63 if (!sendMsg || sendMsg.length > 1261) {
64 alert("err:內容為空或者內容長度超出限制!")
65 $("#msg").val("");
66 return;
67 }
68 var roomOf = $("#headmessages strong").html;
69 socket.emit("chat message", sendMsg, CookieObj.h_imgPath, roomOf);
70 $("#msg").val("");
71 return false;
72 };
73
74 socket.on("sysJoin", function (msg) {
75 var joinInfo = "";
76 joinInfo = "

  • " + msg + "
  • ";
    77 $(joinInfo).appendTo($("#messages")).animate({ "opacity": 0.5 }, 2000, function {
    78 $(this).animate({ "opacity": 1 }, 1500, function {
    79 $(this).animate({ "opacity": 0.3 }, 1000);
    80 });
    81 });
    82 scroll;
    83 });
    84
    85 socket.on("chat message", function (name, msg, img) {
    86 var str = "";
    87 if (name == CookieObj.name) {
    88 str = "

  • " + msg + "

    " + "

  • ";
    89 } else {
    90 str = "

  • " + msg + "

  • ";
    91 }
    92 $("#messages").append(str);
    93 scroll;
    94 });
    95
    96 /*房間選擇*/
    97 //默認是進廣場,從其他房間執行如下函數
    98 $("#selectmenu li").eq(0).on("click", function (e) {
    99 e.stopPropagation;
    100 $("#selectRoom").hide;
    101 $("#headmessages strong").html("Square");
    102 socket.emit("join", "Square", $("#gloableName").html);
    103 $("#messages").empty;
    104 });
    105 $("#selectmenu li").eq(1).on("click", function (e) {
    106 e.stopPropagation;
    107 $("#selectRoom").show;
    108 });
    109 //選擇秦時明月或火影忍者房間
    110 $("#selectRoom li").on("click", function {
    111 var roomName = $(this).children("span").html;
    112 var userName = $("#gloableName").html;
    113 $("#headmessages strong").html(roomName);
    114 socket.emit("join", roomName, userName);
    115 $("#messages").empty;
    116 });
    117
    118
    119
    120 /*
    121 *接收所有已註冊用戶的信息
    122 */
    123 socket.on("onlineUser", function (online) {
    124 var onlineStr = "";
    125 for (var i = 0; i < online.length; i++) { 126 var item = online[i]; 127 onlineStr += "

  • " + item.name + "[Online]
  • ";
    128 }
    129 $("#AllOnline").empty;
    130 $("#oncount").html(online.length);
    131 $("#AllOnline").append(onlineStr);
    132 });
    133 socket.on("outlineUser", function (outline) {
    134 var outlineStr = "";
    135 for (var i = 0; i < outline.length; i++) { 136 var item = outline[i]; 137 outlineStr += "

  • " + item.name + "[Outline]
  • ";
    138 }
    139 $("#AllOutline").empty;
    140 $("#AllOutline").append(outlineStr);
    141 });
    142 socket.on("allUser", function (doc) {
    143 $("#allcount").html(doc.length);
    144 });
    145 socket.on("disconnect", function (name, msg) {
    146 var leftInfo = "";
    147 leftInfo = "

  • " + msg + "
  • ";
    148 $(leftInfo).appendTo($("#messages")).animate({ "opacity": 0.3 }, 2000, function {
    149 $(this).animate({ "opacity": 1 }, 1500, function {
    150 $(this).animate({ "opacity": 0.3 }, 1000);
    151 });
    152 return this;
    153 });
    154 scroll;
    155 });
    156
    157 /*當前房間人員信息*/
    158 var Lastr, r1, r2, r3;
    159 socket.on("SquareRoom", function (roomInfo) {
    160 r1 = roomInfo;
    161 UpdateRoom;
    162 });
    163 socket.on("QinRoom", function (roomInfo) {
    164 r2 = roomInfo;
    165 UpdateRoom;
    166 });
    167 socket.on("NarutoRoom", function (roomInfo) {
    168 r3 = roomInfo;
    169 UpdateRoom;
    170 });
    171 function UpdateRoom {
    172 var $Nowroom = $("#headmessages strong").html, roomCount, roomStr = "";
    173 switch ($Nowroom) {
    174 case "Square": Lastr = r1; break;
    175 case "The Legend of Qin": Lastr = r2; break;
    176 case "Naruto": Lastr = r3; break;
    177 default: Lastr = r1;
    178 }
    179 roomCount = Lastr.length;
    180 for (var i = 0; i < roomCount; i++) { 181 var item = Lastr[i]; 182 roomStr += "

  • " + item.name + "[Online]
  • ";
    183 }
    184 $("#roomCount").html(roomCount);
    185 $("#Roommembers ul").empty;
    186 $("#Roommembers ul").append(roomStr);
    187 }
    188 /*
    189 *切換/退出賬號
    190 */
    191 $("#changeUser").on("click", function {
    192 var res = confirm("Are you sure you want to quit and switch to another account??");
    193 if (res) {
    194 UL;
    195 } else {
    196 $("#control").hide;
    197 $("#setContent").hide;
    198 $("#stateSelect").hide;
    199 }
    200 });
    201 $("#layout").on("click", UL);
    202 function UL {
    203 if (document.cookie) {
    204 $("#loginDiv").addClass("hidden");
    205 $("#main").removeClass("hidden");
    206 var uname = getCookie("userInfo");
    207 CookieObj = JSON.parse(uname.substr(2));
    208 $.ajax({
    209 url: "/layout",
    210 type: "POST",
    211 dataType: "json",
    212 data: {
    213 name: CookieObj.name
    214 }
    215 })
    216 .done(function (data, textStatus, jqXHR) {
    217 if (data.value === "Y") {
    218 clearCookie;
    219 window.location.reload;
    220 }
    221 });
    222 };
    223 }
    224
    225 $("#signinForm #loginBtn").click(onLogin);
    226 $("#signupForm #signupBtn").click(onSignup);
    227 $("#chatMsgForm #send").click(onMsgSubmit);
    228
    229 $("#clear").on("click", function {
    230 $("#messages").empty;
    231 });
    232
    233 /*
    234 *監聽滾動條事件
    235 */
    236 $("#messages").get(0).onscroll = function {
    237 $("#messages .Liright").css("margin-right", 1);
    238 }
    239
    240 /*
    241 *屏蔽回車鍵
    242 */
    243 $(document).keydown(function (event) {
    244 switch (event.keyCode) {
    245 case 13: return false;
    246 }
    247 });
    248 /*
    249 *用戶信息
    250 */
    251 $(".headImg").eq(0).on("click", function (e) {
    252 e.stopPropagation;
    253 if ($("#control").get(0).style.display == "none") {
    254 $("#control").show;
    255 } else {
    256 $("#control").hide;
    257 $("#setContent").hide;
    258 $("#stateSelect").hide;
    259 }
    260 });
    261
    262 /*更改資料*/
    263 $("#set").on("click", function {
    264 $("#setContent").show;
    265 $("#stateSelect").hide;
    266 });
    267 /*構造頭像選擇內容*/
    268 var imgStr = "";
    269 for (var i = 1; i <= 18; i++) { 270 imgStr += "

  • ";
    271 if (i % 6 == 0) {
    272 imgStr += "
    ";
    273 }
    274 }
    275 $("#setThree #imgContent ul").eq(0).append(imgStr);
    276 $("#setThree #imgContent li img").on("click", function (e) {
    277 e.stopPropagation;
    278 var $index = $(this).attr("data-in");
    279 $("#setThree #imgContent img").removeClass("imgSelected");
    280 $("#setThree #imgContent img").eq(($index - 1)).addClass("imgSelected");
    281 });
    282 /*人物頭像模態框*/
    283 $("#setThree").dialog({
    284 autoOpen: false,
    285 title: "Changing Avatar",
    286 modal: true,
    287 width: 578,
    288 resizable: false,
    289 buttons: {
    290 "Ok": function {
    291 var selectedImg = $(".imgSelected").attr("data-in");
    292 // alert(selectedImg);
    293 $.ajax({
    294 url: "/updateImg",
    295 type: "POST",
    296 data: {
    297 name: $("#control div span").eq(0).html,
    298 imgIndex: selectedImg
    299 }
    300 }).done(function (data) {
    301 if (data.value === "Y") {
    302 $("#setThree").dialog("close");
    303 $(".headImg").eq(0).attr("src", "/img/" + selectedImg + ".jpg");
    304 $("#setContent").hide;
    305 $("#control").hide;
    306 // alert(data.msg);
    307 }
    308 });
    309 ;
    310 }
    311 }
    312 });
    313 /*個性簽名模態框*/
    314 $("#setTwo").dialog({
    315 autoOpen: false,
    316 title: "Personalized signature setting",
    317 modal: true,
    318 resizable: false,
    319 buttons: {
    320 "OK": function {
    321 var $newSign = $("#setTwo input[type="text"]").eq(0).val;
    322 if ($newSign != "") {
    323 $.ajax({
    324 url: "/updateSign",
    325 type: "POST",
    326 data: {
    327 name: $("#control div span").eq(0).html,
    328 newSign: $newSign
    329 }
    330 }).done(function (data) {
    331 if (data.value === "Y") {
    332 $("#setTwo p").eq(0).html(data.msg);
    333 setTimeout(function {
    334 $("#control div em").eq(0).html($newSign);
    335 $("#setTwo").dialog("close");
    336 $("#setTwo p").eq(0).html("");
    337 }, 1000);
    338 }
    339 });
    340 }
    341 },
    342 "Cancel": function {
    343 $(this).dialog("close");
    344 }
    345 }
    346 });
    347 /*密碼模態框*/
    348 $("#setOne").dialog({
    349 autoOpen: false,
    350 title: "Changeing User password",
    351 modal: true,
    352 resizable: false,
    353 buttons: {
    354 "Ok": function {
    355 var $oldpass = $("#setOne #oldpass").val, $newpass = $("#setOne #newpass").val;
    356 if ($oldpass != "" && $newpass != "") {
    357 $.ajax({
    358 url: "/changepass",
    359 type: "POST",
    360 data: {
    361 name: $("#control div span").eq(0).html,
    362 oldpass: $oldpass,
    363 newpass: $newpass
    364 }
    365 }).done(function (data, textStatus, jqXHR) {
    366 if (data.value === "Y") {
    367 $("#setOne p").eq(0).html(data.msg);
    368 setTimeout(function {
    369 clearCookie;
    370 $("#setOne p").eq(0).html("");
    371 window.location.reload;
    372 }, 1000);
    373 } else if (data.value === "N") {
    374 $("#setOne p").eq(0).html(data.msg);
    375 $("#setOne #oldpass").val("");
    376 $("#setOne #newpass").val("");
    377 }
    378 });
    379 }
    380 },
    381 "Cancel": function {
    382 $(this).dialog("close");
    383 }
    384 }
    385 });
    386 $("#setContent li").eq(0).click(function (e) {
    387 e.stopPropagation;
    388 $("#setOne").dialog("open");
    389 });
    390 $("#setContent li").eq(1).click(function (e) {
    391 e.stopPropagation;
    392 $("#setTwo").dialog("open");
    393 });
    394 $("#setContent li").eq(2).click(function (e) {
    395 e.stopPropagation;
    396 $("#setThree").dialog("open");
    397 });
    398
    399 /*
    400 *成員信息面板控制:包括所有成員和具體房間成員的狀態
    401 */
    402 $("#rightSide #Roommembers ul").hide;
    403 $("#Allmembers div").css({ "backgroundColor": "rgb(70,130,180)", "color": "white" });
    404 $("#Allmembers div i").addClass("glyphicon glyphicon-triangle-bottom");
    405 $("#Roommembers div i").addClass("glyphicon glyphicon-triangle-right");
    406 $("#rightSide div >div").click(function (e) {
    407 var $title = $(this), $anotherTitle = $(this).parent.siblings("div");
    408 if ($title.next("ul").is(":visible")) {
    409 $title.siblings("ul").hide;
    410 $title.children("i").removeClass("glyphicon glyphicon-triangle-bottom").addClass("glyphicon glyphicon-triangle-right");
    411 $title.css({ "backgroundColor": "", "color": "" });
    412 } else {
    413 $anotherTitle.children("ul").hide;
    414 $anotherTitle.children("div").css({ "backgroundColor": "", "color": "" });
    415 $anotherTitle.children("div").children("i").removeClass("glyphicon glyphicon-triangle-bottom").addClass("glyphicon glyphicon-triangle-right");
    416 $title.css({ "backgroundColor": "rgb(70,130,180)", "color": "white" });
    417 $title.siblings("ul").slideToggle(500).show;
    418 $title.children("i").removeClass("glyphicon glyphicon-triangle-right").addClass("glyphicon glyphicon-triangle-bottom");
    419 }
    420 });
    421
    422 /*函數集*/
    423
    424 /*
    425 *保證scroll始終在最底端
    426 */
    427 function scroll {
    428 $("#messages,#oldMsg ul").animate({
    429 scrollTop: 999999999
    430 }, 0);
    431 }
    432
    433 /*
    434 *刪除cookie
    435 */
    436 function clearCookie {
    437 var keys = document.cookie.match(/[^=;]+(?==)/g);
    438 if (keys) {
    439 var i = keys.length;
    440 while (i--) {
    441 document.cookie = keys[i] + "=0;expires=" + new Date(0).toUTCString;
    442 }
    443 }
    444 }
    445
    446 /*
    447 *獲取cookie
    448 */
    449 function getCookie(sname) {
    450 var aCoookie = document.cookie.split(";");
    451 for (var i = 0; i < aCoookie.length; i++) { 452 var aCrumb = aCoookie[i].split("="); 453 if (sname == aCrumb[0]) 454 return decodeURIComponent(aCrumb[1]); 455 } 456 return null; 457 } 458 459 /* 460 *界面render 461 */ 462 function render { 463 if (document.cookie) { 464 $(".container").addClass("hidden"); 465 $("#main").removeClass("hidden"); 466 var uname = getCookie("userInfo"); 467 CookieObj = JSON.parse(uname.substr(2)); 468 socket.emit("join", $("#headmessages strong").html, CookieObj.name); 469 $(".headImg").eq(0).attr("src", CookieObj.h_imgPath); 470 $("#control div span").eq(0).html(CookieObj.name); 471 $("#control div em").eq(0).html(CookieObj.personalizedSign); 472 }; 473 } 474 $(".emotion").qqFace({ 475 id: "facebox", 476 assign: "msg", 477 path: "img/" //表情存放的路徑 478 }); 479 function replace_em(str) { 480 str = str.replace(//g, ">");
    482 str = str.replace(/
    /g, "
    ");
    483 str = str.replace(/[em_([0-9]*)]/g, "");
    484 return str;
    485 }
    486 /*查詢聊天記錄*/
    487 $("#chatRecord").on("click", function {
    488 $.ajax({
    489 url: "/queryChatMsg",
    490 type: "POST",
    491 data: {
    492 roomName: $("#headmessages strong").html
    493 }
    494 }).done(function (data) {
    495 var Msg = data.msg;
    496 var msgStr = "",
    497 $name = $("#control div span").eq(0).html;
    498 for (var i = 0; i < Msg.length; i++) { 499 var item = Msg[i]; 500 if (item.name == $name) { 501 msgStr += "

  • " + item.name + "  " + item.saytime + "
    " + item.msg + "
  • ";
    502 } else {
    503 msgStr += "

  • " + item.name + "  " + item.saytime + "
    " + item.msg + "
  • ";
    504 }
    505 }
    506 $("#oldMsg ul").empty;
    507 $("#oldMsg ul").css({ "background-img": "url("/img/loading.gif")" });
    508 $("#rightSide").hide;
    509 $("#oldMsg").show;
    510 setTimeout(function {
    511 $("#oldMsg ul").append(msgStr);
    512 scroll;
    513 }, 2000);
    514 });
    515 });
    516
    517 /*關閉歷史記錄窗口*/
    518 $("#oldMsgHead i").on("click", function {
    519 $("#oldMsg ul").empty;
    520 $("#oldMsg").hide;
    521 $("#rightSide").show;
    522 });
    523 /*清空聊天歷史消息*/
    524 $("#clearoldMsg i").on("click", function {
    525 var result = confirm("This action will delete the chat record on the database. Do you want to continue?");
    526 if (result) {
    527 $.ajax({
    528 url: "/deleteMsg",
    529 type: "POST",
    530 data: {
    531 roomName: $("#headmessages strong").html
    532 }
    533 }).done(function (data) {
    534 if (data.value === "Y") {
    535 alert(data.msg);
    536 $("#oldMsg ul").empty;
    537 $("#oldMsg").hide;
    538 $("#rightSide").show;
    539 }
    540 });
    541 }
    542 });
    543 //多行文本輸入框自動聚焦
    544 $("#msg").focus;
    545 //獲取當前城市以及城市天氣
    546 function findWeather {
    547 var cityUrl = "http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js";
    548 $.getScript(cityUrl, function (script, textStatus, jqXHR) {
    549 var citytq = remote_ip_info.city;// 獲取城市
    550 var url = "http://php.weather.sina.com.cn/iframe/index/w_cl.php?code=js&city=" + citytq + "&day=0&dfc=3";
    551 $.ajax({
    552 url: url,
    553 dataType: "script",
    554 scriptCharset: "gbk",
    555 success: function (data) {
    556 var _w = window.SWther.w[citytq][0];
    557 var _f = _w.f1 + "_0.png";
    558 if (new Date.getHours > 17) {
    559 _f = _w.f2 + "_1.png";
    560 }
    561 var img = "";
    563 // var tq = citytq + " " + img + " " + _w.s1 + " " + _w.t1 + "℃~" + _w.t2 + "℃ " + _w.d1 + _w.p1 + "級";
    564 var tq = img + _w.s1 + " " + citytq + "
     " + _w.t2 + "℃~" + (_w.t1 || 25) + "℃ " + "";
    565 $("#weather").html(tq);
    566 }
    567 });
    568 });
    569 }
    570
    571 findWeather;
    572 });

    View Code

    主界面如下圖所示即聊天分為三個模塊(左中右)即:左為功能模塊,用戶可以進行房間的選擇,以及點擊自己的圖像修改個人資料等操作;中為聊天模塊,顯示當前房間聊天內容以及聊天信息輸入框;右為信息展示模塊,默認顯示所有在線用戶信息以及當前房間在線成員信息,用戶可以切換查看當前房間歷史聊天記錄。

    《基於Node.js實現簡易聊天室系列之詳細設計》

    (2)資料庫

    涉及到的技術:mongoDB、mongoose

    由於javascript是一門弱類型語言,所以操作資料庫沒有java、php等語言方便。但是我們可以通過mongoose建立模型model映射到資料庫中去,將對資料庫的操作轉換到操作model中去。

    1 var mongoose = require("mongoose");
    2 var msgRecord=new mongoose.Schema({
    3 name:{
    4 type:String,
    5 index:true,
    6 },
    7 roomName:{
    8 type:String
    9 },
    10 msg:{
    11 type:String,
    12 },
    13 saytime:{
    14 type:String,
    15 }
    16 });
    17 var UserSchema = new mongoose.Schema({
    18 name: {
    19 type: String,
    20 unique: true,
    21 index: true
    22 },
    23 password:{
    24 type: String,
    25 index: true
    26 },
    27 user_id: {
    28 type: mongoose.Schema.Types.ObjectId,
    29 index: true
    30 },
    31 updated: {
    32 type: Date, default: Date.now
    33 },
    34 status: {
    35 type: Boolean,
    36 default: false
    37 },
    38 h_imgPath: {
    39 type: String,
    40 default:"/img/1.jpg"
    41 },
    42 personalizedSign:{
    43 type:String,
    44 default:"Write something will well`"
    45 }
    46 });
    47
    48 var User = mongoose.model("User", UserSchema);
    49 var Msg=mongoose.model("Msg",msgRecord);
    50 module.exports = {
    51 User:User,
    52 Msg:Msg
    53 };

    View Code

    (3)後台

    涉及到的技術:Node.js,socket.io,Express

    後台作為前端和資料庫的橋樑,接收前端傳過來的參數,去請求伺服器,響應不同的服務請求。同時,通過socket.io進行實時通信,實時通信的前提是在客戶端也要引入相關的js文件,通過on和emit方法、自定義事件達到目的

    操作socket.io

    1 var users = {};
    2 var QueryUser = require("./mongoDB/models/model").User;
    3 var Msg = require("./mongoDB/models/model").Msg;
    4 //獲取實時時間
    5 function gettime {
    6 var time = new Date;
    7 var timepartone = time.getFullYear + "-" + (time.getMonth + 1) + "-" + time.getDate + " ";
    8 var timemid = time.getHours, s;
    9 if (timemid < 6) { 10 s = "凌晨 " + timemid; 11 } else if (timemid < 12) { 12 s = "上午 " + timemid; 13 } else if (timemid < 18) { 14 s = "下午 " + "0" + (timemid - 12); 15 } else { 16 s = "晚上 " + (timemid - 12); 17 } 18 var timeparttwo = s + ":" + (time.getMinutes < 10 ? "0" + time.getMinutes : time.getMinutes); 19 return timepartone + timeparttwo; 20 } 21 /*創建三個房間:Square、The Legend of Qin、Naruto*/ 22 var rooms = { "Square": , "The Legend of Qin": , "Naruto": }; 23 var user = ""; 24 module.exports = function (app, io) { 25 io.on("connection", function (socket) { 26 socket.on("join", function (roomName, userName) { 27 user = userName; 28 users[socket.id] = userName; 29 for (var i in rooms) { 30 if (roomName != i) { 31 var index = rooms[i].indexOf(user); 32 if (index !== -1) { 33 console.log("刪除前" + rooms[i]); 34 rooms[i].splice(index, 1); 35 io.to(i).emit("sysLeft", user + "退出了房間" + roomName); 36 socket.leave(i); 37 console.log(userName + "離開了房間" + i + ":這個房間里還有" + rooms[i]); 38 } 39 } 40 } 41 var flag = true; 42 for (var j = 0; j < rooms[roomName].length; j++) { 43 if (rooms[roomName][j] == user) { 44 flag = false; 45 } 46 } 47 if (flag) { 48 rooms[roomName].push(user); 49 socket.join(roomName); 50 } 51 io.sockets.in(roomName).emit("sysJoin", user + "加入了房間" + roomName); 52 total; 53 console.log(user + "加入了" + roomName); 54 }); 55 socket.on("chat message", function (msg, img, roomOf) { 56 var name = ""; 57 name = users[socket.id]; 58 var newMsg = new Msg({ name: name, msg: msg, saytime: gettime,roomName:roomOf }); 59 newMsg.save; 60 if (rooms[roomOf].indexOf(name) === -1) { 61 return false; 62 } 63 console.log(roomOf + ":" + msg); 64 io.sockets.in(roomOf).emit("chat message", name, msg, img); 65 }); 66 socket.on("disconnect", function { 67 var msg = "", name = "", time = ""; 68 time = gettime;; 69 name = users[socket.id]; 70 for (var i in rooms) { 71 var index = rooms[i].indexOf(name); 72 if (index !== -1) { 73 console.log("刪除前" + rooms[i]); 74 rooms[i].splice(index, 1); 75 io.to(i).emit("sysLeft", name + "退出了房間" + i); 76 socket.leave(i); 77 console.log(name + "離開了房間" + i + ":這個房間里還有" + rooms[i]); 78 } 79 } 80 msg = name + "離開群聊 " + time; 81 io.emit("disconnect", name, msg); 82 var timeTotal = total; 83 }); 84 //獲取總用戶 85 function total { 86 QueryUser.find({}, function (err, doc) { 87 io.emit("allUser", doc); 88 }); 89 QueryUser.find({ status: false }, function (err, doc) { 90 io.emit("outlineUser", doc); 91 }); 92 QueryUser.find({ status: true }, function (err, doc) { 93 io.emit("onlineUser", doc); 94 }); 95 //查詢房間里成員的信息 96 /*三個房間:Square、The Legend of Qin、Naruto*/ 97 var F_RMInfo = , S_RMInfo = , T_RMInfo = ; 98 for (var k = 0; k < rooms["Square"].length; k++) { 99 QueryUser.findOne({ name: rooms["Square"][k] }, function (err, doc) { 100 F_RMInfo.push(doc); 101 io.sockets.in("Square").emit("SquareRoom", F_RMInfo); 102 console.log(F_RMInfo); 103 }); 104 } 105 for (var i = 0; i < rooms["The Legend of Qin"].length; i++) { 106 QueryUser.findOne({ name: rooms["The Legend of Qin"][i] }, function (err, doc) { 107 S_RMInfo.push(doc); 108 io.sockets.in("The Legend of Qin").emit("QinRoom", S_RMInfo); 109 console.log(S_RMInfo); 110 }); 111 } 112 for (var j = 0; j < rooms["Naruto"].length; j++) { 113 QueryUser.findOne({ name: rooms["Naruto"][j] }, function (err, doc) { 114 T_RMInfo.push(doc); 115 io.sockets.in("Naruto").emit("NarutoRoom", T_RMInfo); 116 console.log(T_RMInfo); 117 }); 118 } 119 } 120 }); 121 122 };

    View Code

    伺服器js

    1 var express = require("express"),
    2 cookieParser = require("cookie-parser"),
    3 bodyParser = require("body-parser"),
    4 http = require("http"),
    5 path = require("path"),
    6 io = require("socket.io"),
    7 mongoose = require("mongoose"),
    8 app = express,
    9 db,
    10 userRoutes,
    11 socketIO;
    12
    13 /* 資料庫連接 */
    14 mongoose.connect("mongodb://localhost:27017/chatroom");
    15 db = mongoose.connection;
    16 db.on("error", console.error.bind(console, "資料庫連接失敗!"));
    17 db.once("open", function callback {
    18 console.log("資料庫連接成功!");
    19 });
    20
    21 /*Express 配置*/
    22 app.use(cookieParser);
    23 app.use(bodyParser.json);
    24 app.use(bodyParser.urlencoded({ extended: true }));
    25 app.use(express.static(path.join(__dirname, "public")));
    26
    27
    28 http=http.createServer(app,function(req,res){
    29 res.writeHead(200, {"Content-Type": "text/html;charset=utf-8"});
    30 });
    31 io = io(http);
    32
    33 indexRoutes = require("./routes/index")(app);
    34 userRoutes = require("./routes/users")(app);
    35
    36 /*綁定io到伺服器上*/
    37 socketIO = require("./socketIO")(app, io);
    38
    39 http.listen(3000, function {
    40 console.log("listening on *:3000");
    41 });

    View Code

    喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

    本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


    請您繼續閱讀更多來自 科技優家 的精彩文章:

    bboss log4j滾動日誌文件擴展插件使用介紹
    bencode對象編碼實現
    Docker Machine 詳解

    TAG:科技優家 |

    您可能感興趣

    Node.js 專題系列
    基於 hapi的Node.js 小程序後端開發實踐指南
    簡單理解node.js
    Windows系統下如何搭建Node.js伺服器詳解
    Node.js應用Linux部署實戰
    Node.js之express框架
    Node.js 製作驗證碼API
    基於 node.js 的自動路由組件-HttpPostman
    簡單好上手的node.js ORM框架
    Node.js進階:cluster模塊深入剖析
    Node.js 主題周
    大規模集群下的Hadoop NameNode
    blogfoster-scripts:一款簡化 Node.js 項目初始化的工具
    從Nest到Nesk-模塊化Node框架的實踐
    一篇文章教會你 Event loop——瀏覽器和 Node
    瀏覽器與Node的事件循環(Event Loop)有何區別?
    Node.js用戶想學Rust
    Nodejs建站教程:註冊登錄流程的簡單實現
    node+express+mongoDB寫簡單介面,Vue獲取介面
    DOM探索之-DOM的nodeType、nodeName、nodeValue