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

微信扫一扫,分享到朋友圈

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

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

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

一、应用示图

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

二、部分核心源码

前台主要核心逻辑:

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

function sock() { 
    return io.connect("http://localhost:3003"); // http环境下 
} 
// 心跳机制 
document.addEventListener('visibilitychange', function () { 
    if (document.visibilityState == 'hidden') { 
        //记录页面隐藏时间 
        sock() 
        console.log('隐藏了') 
    } 
}) 
setInterval(() => { 
    sock() 
}, 10000); 
var socket = sock() 
var re = document.querySelector("#re"); 
var register1 = document.querySelector(".register"); 
var init = document.querySelector(".init"); 
var passr = document.querySelector("#passr"); 
var passl = document.querySelector("#passl"); 
var login1 = document.querySelector(".login"); 
var register_b = document.querySelector("#register_b"); 
var lo = document.querySelector("#lo"); 
var chat = document.querySelector("#chat"); 
var login_b = document.querySelector("#login_b"); 
var myMes = ""; 
var vf = ""; 
var na = ""; 
var p = ""; 
var we = ""; 
var div = ""; 
var v = ""; 
var q = 0; 
var regCn = /[@:]/im; 
var pattern = /^[\u4E00-\u9FA5]{1,5}$/; 
// 同意 
document.querySelector('.yes').onclick=function () { 
    document.querySelector('.dark').style.display='none' 
} 
document.querySelector('.ys').onclick = function () { 
    document.querySelector('.dark').style.display = 'block' 
} 
// 初始页面注册 
document.querySelector("#reg").onclick = function () { 
    register1.style.display = "block"; 
    init.style.display = "none"; 
    document.querySelector(".bg").style.display = "none"; 
} 
// 初始页面登录 
document.querySelector("#log").onclick = function () { 
    login1.style.display = "block"; 
    init.style.display = "none"; 
    document.querySelector(".bg").style.display = "none"; 
} 
// 登录按钮 
login_b.onclick = function () { 
    login(); 
 
} 
// 注册按钮 
register_b.onclick = function () { 
    register(); 
} 
//发送 
document.getElementById("btn").onclick = function () { 
    send(); 
}; 
// 内容填充 
document.getElementById("text").onkeyup = function () { 
    if (document.getElementById("text").value.length != 0) { 
        document.getElementById("btn").style.cssText = "background:#98E165;color:#fff;" 
    } else { 
        document.getElementById("btn").style.cssText = "background: #DDDEE2;color:#fff" 
    } 
} 
document.querySelector("#text").onclick = function () { 
    document.querySelector('#text').scrollIntoView(false); 
} 
// 传名 
var users2 = ""; 
socket.on('users', function (users) { 
    users2 = users; 
    //  console.log(users2); 
}); 
// 传密码 
var pass2 = "" 
socket.on('pass', function (val) { 
    pass2 = val; 
    //  console.log(pass2) 
}); 
// 统计在线人数 
var arrh = [] 
socket.on('dataval', function (val) { 
    vf = val; 
    console.log(vf); 
 
    for (let i = 0; i < vf.length; i++) { 
        // uu++ 
        arrh.push(vf[i]) 
        console.log(arrh) 
    } 
    var rf = [...new Set(arrh)] 
    console.log(rf) 
    rf = vf 
    for (let j = 0; j < rf.length; j++) { 
        var li = document.createElement("li"); 
        li.classList.add("active"); 
        li.innerText = rf[j] 
        console.log(rf[j]) 
        socket.emit("time", rf[j]); 
        document.querySelector(".fix").appendChild(li); 
 
    } 
}); 
socket.on('join', function (val) { 
    document.querySelector(".fix").innerHTML = '' 
}) 
socket.on('disconnect', function (val) { 
    console.log('离开了') 
    document.querySelector(".fix").innerHTML = '' 
}) 
// 生成数组 
var ar = ""; 
socket.on('array', function (val) { 
    ar = val; 
    // console.log(ar); 
}); 
// 封装注册 
function register() { 
    if (re.value.length == 0) { 
        sweetAlert("请输入用户名!"); 
        return false; 
    } else if (regCn.test(re.value)) { 
        sweetAlert("格式错误,不能够用和:符号取名,请重新输入!"); 
        return false; 
    } else if (pattern.test(re.value)) { 
        sweetAlert("不能使用中文字符哦!"); 
        return false; 
    } else if (!(re.value.length == 0 && regCn.test(re.value))) { 
        if (users2.indexOf(re.value) != -1) { 
            sweetAlert("已经注册啦,换一个用户名吧!"); 
        } else { 
            names(re.value.trim()); 
            pass(passr.value.trim()); 
            sweetAlert("注册成功,您的用户名:" + re.value.trim()); 
            document.querySelector(".swal-button").onclick = function () { 
                window.location.reload(); 
            } 
        } 
    } 
} 
//移动端使用touchend 
var event = navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i) ? 'touchend' : 'click'; 
 
// 选择器 
var Q = function (id) { 
    return document.getElementById(id) 
}; 
//右 
var _right = new mSlider({ 
    dom: ".layer-right", 
    direction: "right" 
}); 
 
Q("btnRight").addEventListener(event, function (e) { 
    _right.open(); 
}) 
// 封装登录 
function login() { 
    if (lo.value.length == 0) { 
        sweetAlert("请输入用户名!"); 
        return false; 
    } else if (regCn.test(lo.value)) { 
        sweetAlert("格式错误,不能够用和:符号取名,请重新输入!"); 
        return false; 
    } else if (pattern.test(lo.value)) { 
        sweetAlert("不能使用中文字符哦!"); 
        return false; 
    } else if (!(lo.value.length == 0 && regCn.test(lo.value))) { 
        if (users2.indexOf(lo.value) != -1) { 
            for (var i = 0; i < users2.length; i++) { 
                if (users2[i] === lo.value && pass2[i] === passl.value) { 
                    if (ar.indexOf(lo.value) == -1) { 
                        sweetAlert("恭喜您,登录成功!"); 
                        socket.emit('setName', lo.value.trim()); 
                        names1(lo.value.trim()); 
                        login1.style.display = "none"; 
                        document.querySelector(".bg").style.display = "none"; 
                        document.querySelector(".cd span").style.display = "none"; 
                        document.querySelector(".title img").style.display = "block"; 
                        document.querySelector(".fix").style.display = "block"; 
                        document.querySelector(".title").style.display = "block"; 
                         _right.open(); 
                        document.querySelector(".swal-button").onclick = function () { 
                            document.getElementById("text").focus(); 
                            document.querySelector(".fix").addEventListener('click', function (e) { 
                                if (e.target.nodeName === "LI" && e.target.innerText != document.title) { 
                                    _right.close(); 
                                    document.querySelector(".chat_b").style.display = "block"; 
                                    document.querySelector(".box").style.display = "block"; 
                                    document.querySelector(".tit").innerText = e.target.innerText; 
                                    document.querySelector(".ys").style.display="none"; 
                                    document.querySelector("#text").focus(); 
                                    onOff = true; 
                                } else { 
                                    sweetAlert("不能跟自己聊天哦~"); 
                                } 
                            }) 
                        } 
                    } else { 
                        sweetAlert("不能重复登录哦!"); 
                        return 
                    } 
                } 
                if (users2[i] === lo.value && pass2[i] != passl.value) { 
                    sweetAlert("密码错误!"); 
                    return; 
                } 
            } 
        } else { 
            sweetAlert("请先注册哦!"); 
            login1.style.display = "none"; 
            register1.style.display = "block"; 
        } 
    } 
} 
// 传名 
function names(value) { 
    this.name = value; 
    socket.emit("reg", name); 
} 
 
function names1(value) { 
    this.name1 = value; 
    socket.emit("join", name1); 
    document.title = name1 
} 
// 传密码 
function pass(value) { 
    socket.emit("pass", value); 
} 
socket.on("join", function (user) { 
    this.na = user; 
}) 
socket.on("reg", function (user) { 
    this.na1 = user; 
}) 
// 私发消息 
socket.on('message1', function (data) { 
    var p1 = document.createElement("div"); 
    var s1 = document.createElement("p"); 
    var s2 = document.createElement("p"); 
    var div1 = document.createElement("div"); 
    var em = document.createElement("em"); 
    var ads = document.createElement("audio"); 
    ads.src = "https://www.maomin.club/data/res.mp3"; 
    ads.className = "ads"; 
    s1.className = "chatlist"; 
    s2.className = "chatlist1"; 
    em.className = "zwasked1"; 
    div1.className = "divbox"; 
    s1.innerText = data.from; 
    s2.innerText = data.msg; 
    s1.appendChild(em); 
    p1.appendChild(s1); 
    p1.appendChild(s2); 
    chat.appendChild(ads); 
    ads.play(); 
    div1.appendChild(p1); 
    chat.appendChild(div1); 
    chat.scrollTop = chat.scrollHeight; 
}); 
// 私聊发送 
function send() { 
    if (document.getElementById("text").value != "") { 
        socket.emit('sayTo', { 
            from: lo.value, 
            to: document.querySelector(".tit").innerText, 
            msg: document.querySelector("#text").value, 
        }) 
        var p1 = document.createElement("div"); 
        var s1 = document.createElement("p"); 
        var s2 = document.createElement("p"); 
        var em = document.createElement("em"); 
        var div1 = document.createElement("div"); 
        var ads = document.createElement("audio"); 
        p1.style.cssText = "float:right;"; 
        s2.style.cssText = "color:#333;" 
        ads.src = "https://www.maomin.club/data/s.wav"; 
        ads.className = "ads"; 
        div1.className = "divbox"; 
        s1.className = "chatlist"; 
        s1.style.cssText = "color:#333 !important;float:right; !important"; 
        s2.className = "chatlist2"; 
        em.className = "zwasked"; 
        s1.innerText = lo.value; 
        s2.innerText = document.querySelector("#text").value; 
        s1.appendChild(em); 
        p1.appendChild(s1); 
        p1.appendChild(s2); 
        chat.appendChild(ads); 
        ads.play(); 
        div1.appendChild(p1); 
        chat.appendChild(div1); 
        chat.scrollTop = chat.scrollHeight; 
    } else { 
        sweetAlert('请输入内容!'); 
    } 
    chat.scrollTop = chat.scrollHeight; 
    document.querySelector("#text").value = ""; 
    document.querySelector("#text").focus(); 
} 

后台主要核心逻辑:

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

var http=require("http"); 
var fs=require("fs"); 
var express = require('express'); 
var ws=require("socket.io"); 
var path=require("path"); 
var _ = require('underscore'); 
var usocket = []; 
var usocket1 = []; 
var pass=[]; 
var data=[]; 
var hashName = {}; 
var onlineCount = 0; 
var app = express(); 
// 静态文件识别 
app.use(express.static(path.join(__dirname, './public'))); 
var server=http.createServer(function (req,res) { 
    var filename = req.url.split('/')[req.url.split('/').length-1]; 
    var suffix = req.url.split('.')[req.url.split('.').length-1]; 
    if(req.url==='/'){ 
        res.writeHead(200, {'Content-Type': 'text/html'}); 
        var html = fs.readFileSync("./public/index.html"); 
        res.end(html) 
    }else if(suffix==='css'){ 
        res.writeHead(200, {'Content-Type': 'text/css'}); 
        res.end(get_file_content(path.join(__dirname, 'public', 'css', filename))); 
    }else if(suffix==='js') { 
        res.writeHead(200, {'Content-Type': 'text/javascript'}); 
        res.end(get_file_content(path.join(__dirname, 'public', 'js', filename))); 
    }else if (suffix in ['gif', 'jpeg', 'jpg', 'png']) { 
        res.writeHead(200, { 
            'Content-Type': 'image/' + suffix 
        }); 
        res.end(get_file_content(path.join(__dirname, 'public', 'images', filename))); 
    } 
}); 
function get_file_content(filepath) { 
    return fs.readFileSync(filepath); 
} 
// 获取在线 
function broadcast() { 
    io.sockets.emit("dataval", hashName); 
} 
//提供私有socket 
function privateSocket(toId) { 
    return (_.findWhere(io.sockets.sockets, { 
        id: toId 
    })); 
} 
// 封装删除 
function removeByValue(arr, val) { 
    for (var i = 0; i < arr.length; i++) { 
        if (arr[i] == val) { 
            arr.splice(i, 1); 
            break; 
        } 
    } 
} 
// 连接socket 
var io=ws(server); 
io.on("connection",function(socket){ 
// 写入成功后读取测试 
fs.readFile('./user.xls', 'utf-8', function (err, data) { 
    if(data!=null){ 
    var value = data.split('\n'); 
     io.sockets.emit("users", value);   
    } 
 
}); 
// 写入成功后读取测试 
fs.readFile('./password.xls', 'utf-8', function (err,data) { 
    if(data!=null){ 
    var pass1=data.split('\n'); 
    io.sockets.emit("pass", pass1); 
    } 
}); 
    broadcast(); 
// 生成名字 
socket.on('setName', function (data) { 
    var name = data; 
    hashName[name] = socket.id; 
    // console.log(hashName[name]); 
    broadcast(); 
}); 
// 私聊发送 
socket.on('sayTo', function (data) { 
    var toName = data.to; 
    var toId; 
    console.log(toName); 
    if (toId = hashName[toName]) { 
        privateSocket(toId).emit('message1', data); 
    } 
}); 
// 离开 
socket.on('disconnect', function (name) { 
         name=this.i2; 
         io.emit("disconnect", name); 
         removeByValue(data, name); 
         io.sockets.emit("dataval", data); 
    }) 
// 在线 
socket.on('time', function (val) { 
        // console.log(val); 
   }) 
// 注册 
socket.on("reg", function (name) { 
          usocket[name] = socket; 
          this.i1=name; 
          io.emit("reg", name); 
          var myname =this.i1+"\n"; 
          fs.writeFile('./user.xls', myname, { 
              'flag': 'a' 
          }, function (err) { 
              if (err) { 
                  throw err; 
              } 
              // 写入成功后读取测试 
              fs.readFile('./user.xls', 'utf-8', function (err,data) { 
                  if (err) { 
                      throw err; 
                  } 
              }); 
          }); 
    }) 
// 加入 
io.emit('connected', ++onlineCount); 
    // console.log(data); 
    io.sockets.emit("array", data); 
    socket.on("join", function (name) { 
        usocket1[name] = socket; 
        this.i2 = name; 
        io.emit("join", name); 
        data.push(name); 
        io.sockets.emit("dataval", data); 
    }) 
// 密码 
socket.on("pass",function(val){ 
      pass[val]=socket; 
      this.i2=val; 
      io.emit("pass", val); 
      var password=this.i2+"\n"; 
       fs.writeFile('./password.xls', password, { 
              'flag': 'a' 
          }, function (err) { 
              if (err) { 
                  throw err; 
              } 
          }); 
    }) 
}); 
server.listen(3003); 
console.log("服务器运行中"); 

三、源码地址

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

https://github.com/maomincoding/chat3

微信扫一扫,分享到朋友圈

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

被 Node.js之父嫌弃,Node.js 如何应对来自 Deno 的挑战

上一篇

2020美国大选结果如何?百度推出实时票数统计数据页面

下一篇

你也可能喜欢

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

长按储存图像,分享给朋友