nodejs websocket 实现简易聊天室功能


首先说明,以下代码都是基于 Nodejs+webSocket搭建多人聊天室实现,我只是复现了一遍,画了张图供自己理解。

数据格式及大致过程简图:
在这里插入图片描述

1. 服务端 app.js 代码

const ws = require('nodejs-websocket')

const broadcast = (str) => {
    server.connections.forEach((connect) => {
        connect.sendText(JSON.stringify(str))
    })
}

const getAllChatter = ()=>{
      let chartterArr = [];
      server.connections.forEach((connect)=>{
          console.log(connect.nickname)
          chartterArr.push({name:connect.nickname})
      });
    return chartterArr;
};

const server = ws.createServer((connect) => {
    connect.on('text', (str) => {
        let data = JSON.parse(str)
        console.log(data);
        switch (data.type) {
            case 'setName': 
                connect.nickname = data.nickname
                // 广播XXX进入房间;
                broadcast({
                    type: 'serverInformation',
                    message: data.nickname + '进入房间'
                })
                // 广播更新在线用户列表
                broadcast({
                    type: 'chatterList',
                    list: getAllChatter()
                })
                break;
            case 'chat': 
                // 广播这条信息;
                broadcast({
                    type: 'chat',
                    name: connect.nickname,
                    message: data.message
                })
                break;
            default: break;
        }
    })

    connect.on('close', () => {
        broadcast({
            type: 'serverInformation',
            message: connect.nickname + '离开房间'
        })

        broadcast({
            type: 'chatterList',
            list: getAllChatter()
        })
    })

    connect.on('error', (err) => {
        console.log(err)
    })
}).listen(3000, () => {
    console.log('server running')
})

2. 客户端 app.html 代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>多人聊天室</title>
    <link rel="stylesheet" href="app.css">
</head>
<body>
    <div class="all">
        <div class = 'person'><text id="onLine">在线人数</text></div>
        <div class="contain">
            <div class="content" id="content"></div>
        </div>
        <div class="footer">
            <input placeholder="设置用户名." name="userName" id="userName"/>
            <button id="setName">设置</button>
            <textarea placeholder="输入您要发送的消息" id="message" name="message"></textarea>
            <button id="sendMessage">发送</button>
        </div>
    </div>

    <div class = "all2">
        <div class="title"><text>在线用户列表:</text></div>
        <div id="userList" class="userList">

        </div>
    </div>

    <script type="text/javascript" language="JavaScript">
        //定义全局的变量
        let ws = null;

        //封装获取时间的函数
        Date.prototype.Format = function (fmt) {
            //author: xjj
            var o = {
                "M+": this.getMonth() + 1, //月份
                "d+": this.getDate(), //日
                "h+": this.getHours(), //小时
                "m+": this.getMinutes(), //分
                "s+": this.getSeconds(), //秒
                "q+": Math.floor((this.getMonth() + 3) / 3), //季度
                "S": this.getMilliseconds() //毫秒
            };
            if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
            for (var k in o)
                if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
            return fmt;
        };

        // 封装:接收后台消息后创建div 
        const createDivWithData = (data) => {
            let outer = document.createElement('div')
            let div_time = document.createElement('p')
            let div_msg = document.createElement('p')

            switch (data.type) {
                case 'serverInformation': 
                    div_time.innerHTML = new Date().Format('yyyy-MM-dd hh:mm:ss')
                    div_msg.innerHTML = data.message;
                    break;

                case 'chat':
                    div_time.innerHTML = new Date().Format('yyyy-MM-dd hh:mm:ss')
                    div_msg.innerHTML = data.name + ':' + data.message;
                    break;
                
            }

            outer.appendChild(div_time)
            outer.appendChild(div_msg)

            return outer
        }

        // 封装:向后台发送消息
        const sendMsgToServer = () => {
            let message = document.getElementById('message')
            if (!message.value) return
            let data = {
                type: 'chat',
                message: message.value
            }
            ws.send(JSON.stringify(data))
            message.value = ''
        }
    
        //封装:向后台设置用户名
        const sendNicknameToServer = () => {
            let setName = document.getElementById('setName')
            setName.onclick = () => {
                let nickName = document.getElementById('userName')
                let data = {
                    type: 'setName',
                    nickname: nickName.value
                }
                if (nickName.value){
                    ws.send(JSON.stringify(data))
                }
                setName.setAttribute('disabled', true);
                setName.style.display = 'none'
                nickName.setAttribute('disabled', true)
            }
        }

        ws = new WebSocket('ws://127.0.0.1:3000')

        ws.onopen = () => {
            sendNicknameToServer()
        }
        
        document.getElementById('sendMessage').onclick = sendMsgToServer

        ws.onmessage = (e) => {
            let data = JSON.parse(e.data)
            if (data.type == 'chatterList') {
                let list = data.list
                let length = list.length
                let chatterList = document.getElementById('userList')
                document.getElementById('onLine').innerText = `在线人数:${length}人`
                
                for(let i = 0; i < length; i++) {
                    let chatterDiv = document.createElement('p')
                    chatterDiv.innerText = list[i].name
                    chatterList.appendChild(chatterDiv)
                }
            } else {
                let con = document.getElementById('content')
                con.appendChild(createDivWithData(data))
            }
            
        }
    </script>
</body>
</html>

3. 样式代码 app.css

.all{
    width: 400px;
    height: 500px;
    border: 1px dotted grey;
    float: left;
    margin-left: 20px;
}
.person {
    width: 400px;
    height: 50px;
    line-height: 50px;
    text-align: center;
}

.contain {
    width: 400px;
    height: 350px;
}

#content{
    width: 99%;
    height: 100%;
    overflow-y: auto;
}

.footer {
    width: 100%;
    height: 100px;
    border: 1px solid green;
    display: flex;
    flex-direction: row;
    align-items: center;
}
.footer input{
    width: 70px;
    height: 50px;
    float: left;
    margin-right: 5px;
    margin-left: 5px;
    border-radius: 5%;
}
.footer button{
    width: 50px;
    height: 50px;
    float: left;
    background-color: deepskyblue;
    border-radius: 10%;
    margin-right: 5px;
}
.footer textarea{
    width: 200px;
    height: 80px;
    overflow-y: scroll;
    float: left;
    margin-right: 5px;
    border-radius: 5%;
}

/*在线用户的列表*/
.all2{
    width: 150px;
    height: 500px;
    border:1px dotted green;
    float: left;
}

.title{
    width: 150px;
    height:50px;
    line-height: 50px;
    background-color: bisque;
}

.userList{
    overflow-y: scroll;
    height: 450px;
}

4. nodemon 辅助开发

安装:npm i nodemon -g --save
启动:nodemon app
避免每次修改服务器代码都要手动重启服务器

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值