基于原生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)