基于原生js 和 ws模块实现简单聊天室
登陆
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title></head><body> <input type="text" id="username" placeholder="请输入用户名"> <button id="enter">进入聊天室</button></body></html><script> ;((doc,storage,location)=>{ const oUsername = doc.querySelector('#username'); const oEnterBtn = doc.querySelector('#enter'); const init = ()=>{ bindEvent(); } function bindEvent(){ oEnterBtn.addEventListener('click',handleEnterBtnClick,false); } function handleEnterBtnClick(){ console.log(oUsername); const username = oUsername.value.trim(); if(username.length < 3 ){ return alert('用户名不能小于3位') }; storage.setItem('username',username); location.href = 'index.html' }; init();})(document,localStorage,location);</script>
聊天
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title></head><body> <ul id="list"></ul> <input type="text" id="message" placeholder="请输入消息"> <button id="send">发送</button></body></html><script> ; ((doc, WebSocket, localStorage, location) => { const oList = doc.querySelector('#list'); const oMsg = doc.querySelector('#message'); const oSendBtn = doc.querySelector('#send'); const ws = new WebSocket('ws://localhost:8000'); let username = '' const init = () => { bindEvent(); } function bindEvent() { oSendBtn.addEventListener('click', handleSendBtnClick, false); ws.addEventListener('open', handleOpen, false); ws.addEventListener('close', handleColse, false); ws.addEventListener('error', handleError, false); ws.addEventListener('message', handleMessage, false); } function handleSendBtnClick() { const msg = oMsg.value; if (!msg.trim().length) return ws.send(JSON.stringify({ user: username, dateTime: new Date().getTime(), message: msg })) oMsg.value = '' } function handleOpen(e) { console.log('open', e); username = localStorage.getItem('username') if (!username) { return location.href = 'entry.html' } } function handleColse(e) { console.log('close', e); } function handleError(e) { console.log('error', e); } function handleMessage(e) { console.log('message', e); const msgData = JSON.parse(e.data); oList.appendChild(createMsg(msgData)) } function createMsg(data) { const { user, dateTime, message } = data; const oItem = doc.createElement('li'); oItem.innerHTML = ` <p> <span>${username}</span> <i>${new Date(dateTime)}</i> </p> <p>消息:${message}</p> ` return oItem } init()})(document, WebSocket, localStorage, location)</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)