JavaScript与Node.js一起打造一款聊天App

开发 前端
聊天是我们人与人交流最直接的方式,互联网的加入使我们交流更加便捷。我们手机上的微信、QQ是我们手机必不可少的应用软件。那么,我们是否可以做一款聊天应用呢?

 聊天是我们人与人交流最直接的方式,互联网的加入使我们交流更加便捷。我们手机上的微信、QQ是我们手机必不可少的应用软件。那么,我们是否可以做一款聊天应用呢?

之前我自己闲着没事,研究过一些技术,做了一款即时通讯应用,下面我将选取几幅具有代表性的图片供大家参考。

一、应用示图

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

以上是这款应用的主要页面,功能可能相对简陋点,不过基本的功能已经实现了,下面我将给出核心代码,全部源码地址在文末。

二、部分核心源码

前台主要核心逻辑:

这里我只列举了js核心代码,查看完整代码可以去文末。

 

  1. function sock() { 
  2.     return io.connect("http://localhost:3003"); // http环境下 
  3. // 心跳机制 
  4. document.addEventListener('visibilitychange'function () { 
  5.     if (document.visibilityState == 'hidden') { 
  6.         //记录页面隐藏时间 
  7.         sock() 
  8.         console.log('隐藏了'
  9.     } 
  10. }) 
  11. setInterval(() => { 
  12.     sock() 
  13. }, 10000); 
  14. var socket = sock() 
  15. var re = document.querySelector("#re"); 
  16. var register1 = document.querySelector(".register"); 
  17. var init = document.querySelector(".init"); 
  18. var passr = document.querySelector("#passr"); 
  19. var passl = document.querySelector("#passl"); 
  20. var login1 = document.querySelector(".login"); 
  21. var register_b = document.querySelector("#register_b"); 
  22. var lo = document.querySelector("#lo"); 
  23. var chat = document.querySelector("#chat"); 
  24. var login_b = document.querySelector("#login_b"); 
  25. var myMes = ""
  26. var vf = ""
  27. var na = ""
  28. var p = ""
  29. var we = ""
  30. var div = ""
  31. var v = ""
  32. var q = 0; 
  33. var regCn = /[@:]/im; 
  34. var pattern = /^[\u4E00-\u9FA5]{1,5}$/; 
  35. // 同意 
  36. document.querySelector('.yes').onclick=function () { 
  37.     document.querySelector('.dark').style.display='none' 
  38. document.querySelector('.ys').onclick = function () { 
  39.     document.querySelector('.dark').style.display = 'block' 
  40. // 初始页面注册 
  41. document.querySelector("#reg").onclick = function () { 
  42.     register1.style.display = "block"
  43.     init.style.display = "none"
  44.     document.querySelector(".bg").style.display = "none"
  45. // 初始页面登录 
  46. document.querySelector("#log").onclick = function () { 
  47.     login1.style.display = "block"
  48.     init.style.display = "none"
  49.     document.querySelector(".bg").style.display = "none"
  50. // 登录按钮 
  51. login_b.onclick = function () { 
  52.     login(); 
  53.  
  54. // 注册按钮 
  55. register_b.onclick = function () { 
  56.     register(); 
  57. //发送 
  58. document.getElementById("btn").onclick = function () { 
  59.     send(); 
  60. }; 
  61. // 内容填充 
  62. document.getElementById("text").onkeyup = function () { 
  63.     if (document.getElementById("text").value.length != 0) { 
  64.         document.getElementById("btn").style.cssText = "background:#98E165;color:#fff;" 
  65.     } else { 
  66.         document.getElementById("btn").style.cssText = "background: #DDDEE2;color:#fff" 
  67.     } 
  68. document.querySelector("#text").onclick = function () { 
  69.     document.querySelector('#text').scrollIntoView(false); 
  70. // 传名 
  71. var users2 = ""
  72. socket.on('users'function (users) { 
  73.     users2 = users; 
  74.     //  console.log(users2); 
  75. }); 
  76. // 传密码 
  77. var pass2 = "" 
  78. socket.on('pass'function (val) { 
  79.     pass2 = val; 
  80.     //  console.log(pass2) 
  81. }); 
  82. // 统计在线人数 
  83. var arrh = [] 
  84. socket.on('dataval'function (val) { 
  85.     vf = val; 
  86.     console.log(vf); 
  87.  
  88.     for (let i = 0; i < vf.length; i++) { 
  89.         // uu++ 
  90.         arrh.push(vf[i]) 
  91.         console.log(arrh) 
  92.     } 
  93.     var rf = [...new Set(arrh)] 
  94.     console.log(rf) 
  95.     rf = vf 
  96.     for (let j = 0; j < rf.length; j++) { 
  97.         var li = document.createElement("li"); 
  98.         li.classList.add("active"); 
  99.         li.innerText = rf[j] 
  100.         console.log(rf[j]) 
  101.         socket.emit("time", rf[j]); 
  102.         document.querySelector(".fix").appendChild(li); 
  103.  
  104.     } 
  105. }); 
  106. socket.on('join'function (val) { 
  107.     document.querySelector(".fix").innerHTML = '' 
  108. }) 
  109. socket.on('disconnect'function (val) { 
  110.     console.log('离开了'
  111.     document.querySelector(".fix").innerHTML = '' 
  112. }) 
  113. // 生成数组 
  114. var ar = ""
  115. socket.on('array'function (val) { 
  116.     ar = val; 
  117.     // console.log(ar); 
  118. }); 
  119. // 封装注册 
  120. function register() { 
  121.     if (re.value.length == 0) { 
  122.         sweetAlert("请输入用户名!"); 
  123.         return false
  124.     } else if (regCn.test(re.value)) { 
  125.         sweetAlert("格式错误,不能够用和:符号取名,请重新输入!"); 
  126.         return false
  127.     } else if (pattern.test(re.value)) { 
  128.         sweetAlert("不能使用中文字符哦!"); 
  129.         return false
  130.     } else if (!(re.value.length == 0 && regCn.test(re.value))) { 
  131.         if (users2.indexOf(re.value) != -1) { 
  132.             sweetAlert("已经注册啦,换一个用户名吧!"); 
  133.         } else { 
  134.             names(re.value.trim()); 
  135.             pass(passr.value.trim()); 
  136.             sweetAlert("注册成功,您的用户名:" + re.value.trim()); 
  137.             document.querySelector(".swal-button").onclick = function () { 
  138.                 window.location.reload(); 
  139.             } 
  140.         } 
  141.     } 
  142. //移动端使用touchend 
  143. var event = navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i) ? 'touchend' : 'click'
  144.  
  145. // 选择器 
  146. var Q = function (id) { 
  147.     return document.getElementById(id) 
  148. }; 
  149. //右 
  150. var _right = new mSlider({ 
  151.     dom: ".layer-right"
  152.     direction: "right" 
  153. }); 
  154.  
  155. Q("btnRight").addEventListener(event, function (e) { 
  156.     _right.open(); 
  157. }) 
  158. // 封装登录 
  159. function login() { 
  160.     if (lo.value.length == 0) { 
  161.         sweetAlert("请输入用户名!"); 
  162.         return false
  163.     } else if (regCn.test(lo.value)) { 
  164.         sweetAlert("格式错误,不能够用和:符号取名,请重新输入!"); 
  165.         return false
  166.     } else if (pattern.test(lo.value)) { 
  167.         sweetAlert("不能使用中文字符哦!"); 
  168.         return false
  169.     } else if (!(lo.value.length == 0 && regCn.test(lo.value))) { 
  170.         if (users2.indexOf(lo.value) != -1) { 
  171.             for (var i = 0; i < users2.length; i++) { 
  172.                 if (users2[i] === lo.value && pass2[i] === passl.value) { 
  173.                     if (ar.indexOf(lo.value) == -1) { 
  174.                         sweetAlert("恭喜您,登录成功!"); 
  175.                         socket.emit('setName', lo.value.trim()); 
  176.                         names1(lo.value.trim()); 
  177.                         login1.style.display = "none"
  178.                         document.querySelector(".bg").style.display = "none"
  179.                         document.querySelector(".cd span").style.display = "none"
  180.                         document.querySelector(".title img").style.display = "block"
  181.                         document.querySelector(".fix").style.display = "block"
  182.                         document.querySelector(".title").style.display = "block"
  183.                          _right.open(); 
  184.                         document.querySelector(".swal-button").onclick = function () { 
  185.                             document.getElementById("text").focus(); 
  186.                             document.querySelector(".fix").addEventListener('click'function (e) { 
  187.                                 if (e.target.nodeName === "LI" && e.target.innerText != document.title) { 
  188.                                     _right.close(); 
  189.                                     document.querySelector(".chat_b").style.display = "block"
  190.                                     document.querySelector(".box").style.display = "block"
  191.                                     document.querySelector(".tit").innerText = e.target.innerText; 
  192.                                     document.querySelector(".ys").style.display="none"
  193.                                     document.querySelector("#text").focus(); 
  194.                                     onOff = true
  195.                                 } else { 
  196.                                     sweetAlert("不能跟自己聊天哦~"); 
  197.                                 } 
  198.                             }) 
  199.                         } 
  200.                     } else { 
  201.                         sweetAlert("不能重复登录哦!"); 
  202.                         return 
  203.                     } 
  204.                 } 
  205.                 if (users2[i] === lo.value && pass2[i] != passl.value) { 
  206.                     sweetAlert("密码错误!"); 
  207.                     return
  208.                 } 
  209.             } 
  210.         } else { 
  211.             sweetAlert("请先注册哦!"); 
  212.             login1.style.display = "none"
  213.             register1.style.display = "block"
  214.         } 
  215.     } 
  216. // 传名 
  217. function names(value) { 
  218.     this.name = value; 
  219.     socket.emit("reg"name); 
  220.  
  221. function names1(value) { 
  222.     this.name1 = value; 
  223.     socket.emit("join", name1); 
  224.     document.title = name1 
  225. // 传密码 
  226. function pass(value) { 
  227.     socket.emit("pass", value); 
  228. socket.on("join"function (user) { 
  229.     this.na = user
  230. }) 
  231. socket.on("reg"function (user) { 
  232.     this.na1 = user
  233. }) 
  234. // 私发消息 
  235. socket.on('message1'function (data) { 
  236.     var p1 = document.createElement("div"); 
  237.     var s1 = document.createElement("p"); 
  238.     var s2 = document.createElement("p"); 
  239.     var div1 = document.createElement("div"); 
  240.     var em = document.createElement("em"); 
  241.     var ads = document.createElement("audio"); 
  242.     ads.src = "https://www.maomin.club/data/res.mp3"
  243.     ads.className = "ads"
  244.     s1.className = "chatlist"
  245.     s2.className = "chatlist1"
  246.     em.className = "zwasked1"
  247.     div1.className = "divbox"
  248.     s1.innerText = data.from
  249.     s2.innerText = data.msg; 
  250.     s1.appendChild(em); 
  251.     p1.appendChild(s1); 
  252.     p1.appendChild(s2); 
  253.     chat.appendChild(ads); 
  254.     ads.play(); 
  255.     div1.appendChild(p1); 
  256.     chat.appendChild(div1); 
  257.     chat.scrollTop = chat.scrollHeight; 
  258. }); 
  259. // 私聊发送 
  260. function send() { 
  261.     if (document.getElementById("text").value != "") { 
  262.         socket.emit('sayTo', { 
  263.             from: lo.value, 
  264.             to: document.querySelector(".tit").innerText, 
  265.             msg: document.querySelector("#text").value, 
  266.         }) 
  267.         var p1 = document.createElement("div"); 
  268.         var s1 = document.createElement("p"); 
  269.         var s2 = document.createElement("p"); 
  270.         var em = document.createElement("em"); 
  271.         var div1 = document.createElement("div"); 
  272.         var ads = document.createElement("audio"); 
  273.         p1.style.cssText = "float:right;"
  274.         s2.style.cssText = "color:#333;" 
  275.         ads.src = "https://www.maomin.club/data/s.wav"
  276.         ads.className = "ads"
  277.         div1.className = "divbox"
  278.         s1.className = "chatlist"
  279.         s1.style.cssText = "color:#333 !important;float:right; !important"
  280.         s2.className = "chatlist2"
  281.         em.className = "zwasked"
  282.         s1.innerText = lo.value; 
  283.         s2.innerText = document.querySelector("#text").value; 
  284.         s1.appendChild(em); 
  285.         p1.appendChild(s1); 
  286.         p1.appendChild(s2); 
  287.         chat.appendChild(ads); 
  288.         ads.play(); 
  289.         div1.appendChild(p1); 
  290.         chat.appendChild(div1); 
  291.         chat.scrollTop = chat.scrollHeight; 
  292.     } else { 
  293.         sweetAlert('请输入内容!'); 
  294.     } 
  295.     chat.scrollTop = chat.scrollHeight; 
  296.     document.querySelector("#text").value = ""
  297.     document.querySelector("#text").focus(); 

后台主要核心逻辑:

我这里只列举了http环境的,完整代码中有https环境的。

 

  1. var http=require("http"); 
  2. var fs=require("fs"); 
  3. var express = require('express'); 
  4. var ws=require("socket.io"); 
  5. var path=require("path"); 
  6. var _ = require('underscore'); 
  7. var usocket = []; 
  8. var usocket1 = []; 
  9. var pass=[]; 
  10. var data=[]; 
  11. var hashName = {}; 
  12. var onlineCount = 0; 
  13. var app = express(); 
  14. // 静态文件识别 
  15. app.use(express.static(path.join(__dirname, './public'))); 
  16. var server=http.createServer(function (req,res) { 
  17.     var filename = req.url.split('/')[req.url.split('/').length-1]; 
  18.     var suffix = req.url.split('.')[req.url.split('.').length-1]; 
  19.     if(req.url==='/'){ 
  20.         res.writeHead(200, {'Content-Type''text/html'}); 
  21.         var html = fs.readFileSync("./public/index.html"); 
  22.         res.end(html) 
  23.     }else if(suffix==='css'){ 
  24.         res.writeHead(200, {'Content-Type''text/css'}); 
  25.         res.end(get_file_content(path.join(__dirname, 'public''css', filename))); 
  26.     }else if(suffix==='js') { 
  27.         res.writeHead(200, {'Content-Type''text/javascript'}); 
  28.         res.end(get_file_content(path.join(__dirname, 'public''js', filename))); 
  29.     }else if (suffix in ['gif''jpeg''jpg''png']) { 
  30.         res.writeHead(200, { 
  31.             'Content-Type''image/' + suffix 
  32.         }); 
  33.         res.end(get_file_content(path.join(__dirname, 'public''images', filename))); 
  34.     } 
  35. }); 
  36. function get_file_content(filepath) { 
  37.     return fs.readFileSync(filepath); 
  38. // 获取在线 
  39. function broadcast() { 
  40.     io.sockets.emit("dataval", hashName); 
  41. //提供私有socket 
  42. function privateSocket(toId) { 
  43.     return (_.findWhere(io.sockets.sockets, { 
  44.         id: toId 
  45.     })); 
  46. // 封装删除 
  47. function removeByValue(arr, val) { 
  48.     for (var i = 0; i < arr.length; i++) { 
  49.         if (arr[i] == val) { 
  50.             arr.splice(i, 1); 
  51.             break; 
  52.         } 
  53.     } 
  54. // 连接socket 
  55. var io=ws(server); 
  56. io.on("connection",function(socket){ 
  57. // 写入成功后读取测试 
  58. fs.readFile('./user.xls''utf-8'function (err, data) { 
  59.     if(data!=null){ 
  60.     var value = data.split('\n'); 
  61.      io.sockets.emit("users", value);   
  62.     } 
  63.  
  64. }); 
  65. // 写入成功后读取测试 
  66. fs.readFile('./password.xls''utf-8'function (err,data) { 
  67.     if(data!=null){ 
  68.     var pass1=data.split('\n'); 
  69.     io.sockets.emit("pass", pass1); 
  70.     } 
  71. }); 
  72.     broadcast(); 
  73. // 生成名字 
  74. socket.on('setName'function (data) { 
  75.     var name = data; 
  76.     hashName[name] = socket.id; 
  77.     // console.log(hashName[name]); 
  78.     broadcast(); 
  79. }); 
  80. // 私聊发送 
  81. socket.on('sayTo'function (data) { 
  82.     var toName = data.to
  83.     var toId; 
  84.     console.log(toName); 
  85.     if (toId = hashName[toName]) { 
  86.         privateSocket(toId).emit('message1', data); 
  87.     } 
  88. }); 
  89. // 离开 
  90. socket.on('disconnect'function (name) { 
  91.          name=this.i2; 
  92.          io.emit("disconnect"name); 
  93.          removeByValue(data, name); 
  94.          io.sockets.emit("dataval", data); 
  95.     }) 
  96. // 在线 
  97. socket.on('time'function (val) { 
  98.         // console.log(val); 
  99.    }) 
  100. // 注册 
  101. socket.on("reg"function (name) { 
  102.           usocket[name] = socket; 
  103.           this.i1=name
  104.           io.emit("reg"name); 
  105.           var myname =this.i1+"\n"
  106.           fs.writeFile('./user.xls', myname, { 
  107.               'flag''a' 
  108.           }, function (err) { 
  109.               if (err) { 
  110.                   throw err; 
  111.               } 
  112.               // 写入成功后读取测试 
  113.               fs.readFile('./user.xls''utf-8'function (err,data) { 
  114.                   if (err) { 
  115.                       throw err; 
  116.                   } 
  117.               }); 
  118.           }); 
  119.     }) 
  120. // 加入 
  121. io.emit('connected', ++onlineCount); 
  122.     // console.log(data); 
  123.     io.sockets.emit("array", data); 
  124.     socket.on("join"function (name) { 
  125.         usocket1[name] = socket; 
  126.         this.i2 = name
  127.         io.emit("join"name); 
  128.         data.push(name); 
  129.         io.sockets.emit("dataval", data); 
  130.     }) 
  131. // 密码 
  132. socket.on("pass",function(val){ 
  133.       pass[val]=socket; 
  134.       this.i2=val; 
  135.       io.emit("pass", val); 
  136.       var password=this.i2+"\n"
  137.        fs.writeFile('./password.xls'password, { 
  138.               'flag''a' 
  139.           }, function (err) { 
  140.               if (err) { 
  141.                   throw err; 
  142.               } 
  143.           }); 
  144.     }) 
  145. }); 
  146. server.listen(3003); 
  147. console.log("服务器运行中"); 

三、源码地址

这个项目是之前写的,欢迎大家进行指正。大家可以复制下面的源码地址,拉取下来就可以在本地实现一个聊天服务。如果你有服务器可以把它部署在服务器上,这样你就可以有一个属于自己的聊天App了。大家可以根据源码进行学习,有不明白的可以随时问我。

https://github.com/maomincoding/chat3

责任编辑:华轩 来源: 前端历劫之路
相关推荐

2023-06-20 06:44:14

Node.jsCPU 负载

2021-10-12 23:45:43

NodeJs事件

2022-11-14 00:14:49

2014-04-01 11:02:00

Node.jsWeb Socket聊天程序

2022-10-28 15:51:24

JavaScript开发Node.js

2021-09-15 19:02:42

Node.jsFs模块

2014-12-16 10:11:22

2016-12-08 11:49:03

APPRetrofitRxJava

2021-02-01 08:16:14

ChromeNode.js

2020-12-22 06:02:48

JS聚合聊天

2014-10-30 10:28:55

Node.js

2022-02-17 10:26:17

JavaScript扫雷游戏前端

2015-08-18 09:11:34

杜长伟APP

2021-11-24 08:51:32

Node.js监听函数

2015-12-25 16:31:54

开源攻防平台DVNA

2017-04-10 13:28:32

Node.jsJavaScript

2015-12-24 16:33:42

2011-12-18 18:32:35

APP

2021-11-17 15:36:04

鸿蒙HarmonyOS应用

2022-03-04 09:05:55

StarRocks数据湖数据质量
点赞
收藏

51CTO技术栈公众号