400-028-6601
建站资讯

网站建设资讯

为你提供网站建设行业资讯、网站优化知识、主机域名邮箱、网站开发常见问题等。

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

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

创新互联主要从事网站设计制作、网站建设、网页设计、企业做网站、公司建网站等业务。立足成都服务正定,10余年网站建设经验,价格优惠、服务专业,欢迎来电咨询建站服务:18982081108

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

一、应用示图

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

二、部分核心源码

前台主要核心逻辑:

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

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

后台主要核心逻辑:

我这里只列举了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. // 获取在线 
  40. function broadcast() { 
  41.     io.sockets.emit("dataval", hashName); 
  42. } 
  43. //提供私有socket 
  44. function privateSocket(toId) { 
  45.     return (_.findWhere(io.sockets.sockets, { 
  46.         id: toId 
  47.     })); 
  48. } 
  49. // 封装删除 
  50. function removeByValue(arr, val) { 
  51.     for (var i = 0; i < arr.length; i++) { 
  52.         if (arr[i] == val) { 
  53.             arr.splice(i, 1); 
  54.             break; 
  55.         } 
  56.     } 
  57. } 
  58. // 连接socket 
  59. var io=ws(server); 
  60. io.on("connection",function(socket){ 
  61. // 写入成功后读取测试 
  62. fs.readFile('./user.xls', 'utf-8', function (err, data) { 
  63.     if(data!=null){ 
  64.     var value = data.split('\n'); 
  65.      io.sockets.emit("users", value);   
  66.     } 
  67.  
  68. }); 
  69. // 写入成功后读取测试 
  70. fs.readFile('./password.xls', 'utf-8', function (err,data) { 
  71.     if(data!=null){ 
  72.     var pass1=data.split('\n'); 
  73.     io.sockets.emit("pass", pass1); 
  74.     } 
  75. }); 
  76.     broadcast(); 
  77. // 生成名字 
  78. socket.on('setName', function (data) { 
  79.     var name = data; 
  80.     hashName[name] = socket.id; 
  81.     // console.log(hashName[name]); 
  82.     broadcast(); 
  83. }); 
  84. // 私聊发送 
  85. socket.on('sayTo', function (data) { 
  86.     var toName = data.to; 
  87.     var toId; 
  88.     console.log(toName); 
  89.     if (toId = hashName[toName]) { 
  90.         privateSocket(toId).emit('message1', data); 
  91.     } 
  92. }); 
  93. // 离开 
  94. socket.on('disconnect', function (name) { 
  95.          name=this.i2; 
  96.          io.emit("disconnect", name); 
  97.          removeByValue(data, name); 
  98.          io.sockets.emit("dataval", data); 
  99.     }) 
  100. // 在线 
  101. socket.on('time', function (val) { 
  102.         // console.log(val); 
  103.    }) 
  104. // 注册 
  105. socket.on("reg", function (name) { 
  106.           usocket[name] = socket; 
  107.           this.i1=name; 
  108.           io.emit("reg", name); 
  109.           var myname =this.i1+"\n"; 
  110.           fs.writeFile('./user.xls', myname, { 
  111.               'flag': 'a' 
  112.           }, function (err) { 
  113.               if (err) { 
  114.                   throw err; 
  115.               } 
  116.               // 写入成功后读取测试 
  117.               fs.readFile('./user.xls', 'utf-8', function (err,data) { 
  118.                   if (err) { 
  119.                       throw err; 
  120.                   } 
  121.               }); 
  122.           }); 
  123.     }) 
  124. // 加入 
  125. io.emit('connected', ++onlineCount); 
  126.     // console.log(data); 
  127.     io.sockets.emit("array", data); 
  128.     socket.on("join", function (name) { 
  129.         usocket1[name] = socket; 
  130.         this.i2 = name; 
  131.         io.emit("join", name); 
  132.         data.push(name); 
  133.         io.sockets.emit("dataval", data); 
  134.     }) 
  135. // 密码 
  136. socket.on("pass",function(val){ 
  137.       pass[val]=socket; 
  138.       this.i2=val; 
  139.       io.emit("pass", val); 
  140.       var password=this.i2+"\n"; 
  141.        fs.writeFile('./password.xls', password, { 
  142.               'flag': 'a' 
  143.           }, function (err) { 
  144.               if (err) { 
  145.                   throw err; 
  146.               } 
  147.           }); 
  148.     }) 
  149. }); 
  150. server.listen(3003); 
  151. console.log("服务器运行中"); 

三、源码地址

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

https://github.com/maomincoding/chat3


当前文章:JavaScript与Node.js一起打造一款聊天App
文章转载:http://www.hnjierui.cn/article/djhcsis.html

其他资讯