基于原生js 和 ws模块实现简单聊天室

登陆

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Document</title>
  7. </head>
  8. <body>
  9. <input type="text" id="username" placeholder="请输入用户名">
  10. <button id="enter">进入聊天室</button>
  11. </body>
  12. </html>
  13. <script>
  14. ;((doc,storage,location)=>{
  15. const oUsername = doc.querySelector('#username');
  16. const oEnterBtn = doc.querySelector('#enter');
  17. const init = ()=>{
  18. bindEvent();
  19. }
  20. function bindEvent(){
  21. oEnterBtn.addEventListener('click',handleEnterBtnClick,false);
  22. }
  23. function handleEnterBtnClick(){
  24. console.log(oUsername);
  25. const username = oUsername.value.trim();
  26. if(username.length < 3 ){
  27. return alert('用户名不能小于3位')
  28. };
  29. storage.setItem('username',username);
  30. location.href = 'index.html'
  31. };
  32. init();
  33. })(document,localStorage,location);
  34. </script>

聊天

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Document</title>
  7. </head>
  8. <body>
  9. <ul id="list"></ul>
  10. <input type="text" id="message" placeholder="请输入消息">
  11. <button id="send">发送</button>
  12. </body>
  13. </html>
  14. <script>
  15. ; ((doc, WebSocket, localStorage, location) => {
  16. const oList = doc.querySelector('#list');
  17. const oMsg = doc.querySelector('#message');
  18. const oSendBtn = doc.querySelector('#send');
  19. const ws = new WebSocket('ws://localhost:8000');
  20. let username = ''
  21. const init = () => {
  22. bindEvent();
  23. }
  24. function bindEvent() {
  25. oSendBtn.addEventListener('click', handleSendBtnClick, false);
  26. ws.addEventListener('open', handleOpen, false);
  27. ws.addEventListener('close', handleColse, false);
  28. ws.addEventListener('error', handleError, false);
  29. ws.addEventListener('message', handleMessage, false);
  30. }
  31. function handleSendBtnClick() {
  32. const msg = oMsg.value;
  33. if (!msg.trim().length) return
  34. ws.send(JSON.stringify({
  35. user: username,
  36. dateTime: new Date().getTime(),
  37. message: msg
  38. }))
  39. oMsg.value = ''
  40. }
  41. function handleOpen(e) {
  42. console.log('open', e);
  43. username = localStorage.getItem('username')
  44. if (!username) {
  45. return location.href = 'entry.html'
  46. }
  47. }
  48. function handleColse(e) {
  49. console.log('close', e);
  50. }
  51. function handleError(e) {
  52. console.log('error', e);
  53. }
  54. function handleMessage(e) {
  55. console.log('message', e);
  56. const msgData = JSON.parse(e.data);
  57. oList.appendChild(createMsg(msgData))
  58. }
  59. function createMsg(data) {
  60. const { user, dateTime, message } = data;
  61. const oItem = doc.createElement('li');
  62. oItem.innerHTML = `
  63. <p>
  64. <span>${username}</span>
  65. <i>${new Date(dateTime)}</i>
  66. </p>
  67. <p>消息:${message}</p>
  68. `
  69. return oItem
  70. }
  71. init()
  72. })(document, WebSocket, localStorage, location)
  73. </script>

ws模块

const Ws = require('ws');

;((ws)=>{
    const server  = new ws.Server({
        port:8000
    })

    const init = ()=>{
        bindEvent();
    }

    function bindEvent(){
        server.on('open',handleOpen)
        server.on('close',handleClose)
        server.on('error',handleError)
        server.on('connection',handleConnection)
    }

    function handleOpen(){
        console.log('ws oepn');
    }
    function handleClose(){
        console.log('ws close');
    }
    function handleError(){
        console.log('ws error');
    }
    function handleConnection(ws){
        console.log('ws connection');
        ws.on('message',handlMessage)
    }

    function handlMessage(msg){
        console.log(msg);
        //  clients 所有客户端 => 把消息发送给每个客户端
        server.clients.forEach((c)=>{
            c.send(msg)
        })
    }
    init()

})(Ws)

心脏跳动

<script>
    let lock = false;   //避免重复连接
    const wsUrl = "ws://localhost:8000";
    let ws = null;
    createWebSocket();

    //  创建websoket
    function createWebSocket() {
        try {
            ws = new WebSocket(wsUrl);
            websocketInit();
        } catch (e) {
            console.log('catch');
            websocketReconnect(wsUrl);
        }
    }

    function websocketInit() {
        ws.onopen = function (e) {
            ws.send(10);
            //心跳检测重置
            heartCheck.start();
        };
        // 断开 web socket 连接成功触发事件
        ws.onclose = function (e) {
            websocketReconnect(wsUrl);
            console.log("连接已关闭...");
        };
        // 接收服务端数据时触发事件
        ws.onmessage = function (e) {
            console.log(e.data);
            heartCheck.start();
        };
        // 通信发生错误时触发
        ws.onerror = function (e) {
            websocketReconnect(wsUrl);
            console.log('通信错误:' + e.data);
        };
    };

    //  重新连接websoket
    function websocketReconnect(url) {
        if (lock) return;

        lock = true;
        //没连接上会一直重连,设置延迟避免请求过多
        tt && clearTimeout(tt);
        var tt = setTimeout(function () {
            createWebSocket(url);
            lock = false;
        }, 5000);
    }

    //心跳检测
    var heartCheck = {
        timeout: 5000,
        timeoutObj: null,
        serverTimeoutObj: null,
        start: function () {
            var self = this;
            this.timeoutObj && clearTimeout(this.timeoutObj);
            this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
            this.timeoutObj = setTimeout(function () {
                //发送测试信息,后端收到后,返回一个消息,
                ws.send("reset");
                self.serverTimeoutObj = setTimeout(function () {
                    ws.close();
                }, self.timeout);
            }, this.timeout)
        }
    }

</script>
const ws = require('ws');
const express = require('express');
const app = express();
const path = require('path');
app.use(express.static(path.join(__dirname, 'public')));


const server = new ws.Server({
    port: 8000
})

server.on('connection', (childs: any) => {
    //  主动给C端发送消息
    for (let i = 0; i < 10; i++) {
        childs.send(`第一次:${i}`)
    }

    //  接受c端消息
    childs.on('message', (e) => {
        console.log(e); //  接受前端发送的从连命令
        for (let i = 0; i < 10; i++) {
            childs.send(`重新连接:${i}`)
        }
    })
})

app.listen(9000)