跟着教学视频了解到websocket和socket.io的通信方法之后,自己写了一个交互效果更好的聊天室。
▍演示效果
▍实现过程(Windows系统)
1、在nodeJS中文网下载nodeJS客户端并安装;
2、在桌面(未知可自选)创建一个项目文件夹用于存放相关文件;
3、打开新建的文件夹,创建chatRoom.html文件和server.js文件;
4、打开命令行窗口,找到这个文件夹后,输入【npm i socket.io】,此时将在该文件夹中生成了一个新的文件夹,这是刚刚下载的socket.io相关依赖包;
5、将代码补充到chatRoom.html文件和server.js文件中;
6、打开命令行窗口,找到该项目文件夹后,输入【server.js】并【Enter】。
7、保持窗口在运行状态,不要关闭!!!
▍有待完善的地方
1、没有实现动态的分配身份;
2、界面可再优化;
3、前台向后台发送中文姓名时会出现乱码(找了两天资料都没有搞定,跪求大佬指教)。
▍server.js
// 引入http标准模块,CommonJS模块
const http = require("http");
const fs = require("fs");
const ws = require("socket.io");
// 当前在线人数
let count = 0;
// 总访客人数
let totalCount = 0;
// 创建一个web服务器
const server = http.createServer(function(request, response) {
response.writeHead(200, {
"Content-Type": "text/html;charset=UTF-8"
});
// 读取文件
const html = fs.readFileSync("chatRoom.html");
response.end(html);
});
// 基于当前web服务器开启socket实例
const io = ws(server);
// 检测连接事件
io.on("connection", function(socket) {
console.log("当前有用户连接");
count++;
totalCount++;
console.log("count:" + count);
let name = '';
// 加入群聊
socket.on("join", function(message) {
console.log(message);
name = message.name;
console.log(name + "加入了群聊");
// 给公众发消息
socket.broadcast.emit("joinNoticeOther", {
name: name,
action: "加入了群聊",
count: count
});
// 给自己发消息
socket.emit("joinNoticeSelf", {
count: count,
id: totalCount
});
});
// 接收客户端所发送的信息
socket.on("message", function(message) {
console.log(message);
// 向所有客户端广播发布的消息
io.emit("message", message);
});
// 监听到连接断开
socket.on("disconnect", function() {
count--;
console.log(name + "离开了群聊")
io.emit("disconnection", {
count: count,
name: name
});
});
});
// 服务器监听端口
server.listen(3000);
▍chatRoom.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>蜗牛先生的聊天室</title>
<style>
* {
margin: 0;
padding: 0;
}
html {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
background-color: #DDDDDD;
}
.chatroom {
width: 1000px;
height: 600px;
display: flex;
border-radius: 20px;
overflow: hidden;
opacity: 0.7;
box-shadow: 0 0 3px 3px #BBBBBB;
}
.left {
width: 30%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-content: center;
background-color: #F0F0F0;
}
.icon-container {
height: 30%;
display: flex;
justify-content: center;
align-items: center;
}
.icon-container img {
width: 150px;
height: 150px;
object-fit: cover;
border-radius: 50%;
}
.self-container {
height: 30%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
line-height: 60px;
}
.self-container .id {
font-size: 30px;
font-weight: bold;
}
.self-container .content {
display: flex;
flex-direction: row;
justify-content: space-around;
font-size: 22px;
}
.note-container {
/*margin: 10px;*/
padding: 5px;
height: 30%;
/*border-radius: 10px;*/
/*background-color: white;*/
}
.right {
/*border-left: 1px solid #888888;*/
width: 70%;
height: 100%;
/*background-image: url(http://p4.so.qhmsg.com/bdr/_240_/t010d7efb6430fb56d9.jpg);*/
background-color: #EEEEEE;
}
.right .head {
height: 10%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
background-color: white;
font-size: 22px;
font-weight: bold;
}
.right .chat-container {
padding: 10px;
height: 80%;
overflow-y: scroll;
background-color: #F5F5F5;
background-image: url(http://tool.uixsj.cn/qchan/uploads/2018/08/traffic_a_lot_of_cars_driving_across_the_golden_gate_bridge_free_stock_photos_picjumbo_HNCK2899_2210x1474.jpg);
box-sizing: border-box;
}
/*滚动条样式*/
.right .chat-container::-webkit-scrollbar {
/*滚动条整体样式*/
width: 8px;
/*高宽分别对应横竖滚动条的尺寸*/
height: 8px;
}
.right .chat-container::-webkit-scrollbar-thumb {
/*滚动条里面小方块*/
border-radius: 2rem;
/*-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);*/
background-color: #AAAAAA;
}
.right .chat-container::-webkit-scrollbar-track {
/*滚动条里面轨道*/
/*-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);*/
border-radius: 2rem;
background-color: transparent;
}
.right .chat-container .message-self,
.right .chat-container .message-other {
padding: 10px;
box-sizing: border-box;
}
.right .chat-container .message-self {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-end;
}
.right .chat-container .message-other {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
/*justify-content: flex-start;*/
}
.right .chat-container .message-container {
max-width: 80%;
/*height: auto;*/
display: flex;
flex-direction: row;
/*box-sizing: border-box;*/
}
.right .chat-container .message-self .message-container .message-content {
padding-right: 10px;
}
.right .chat-container .message-other .message-container .message-content {
padding-left: 10px;
}
.right .chat-container .message-self .message-container .message-content .message {
background-color: blue;
color: white;
}
.right .chat-container .message-other .message-container .message-content .message {
background-color: white;
color: black;
}
.right .chat-container .message-container .message-content .name {
font-size: 12px;
padding: 5px 0;
color: #888888;
}
.right .chat-container .message-self .message-container .message-content .name {
text-align: right;
}
.right .chat-container .message-other .message-container .message-content .name {
text-align: left;
}
.right .chat-container .message-container .message-content .message {
border-radius: 10px;
padding: 10px;
}
.right .chat-container .message-container .icon img {
width: 40px;
height: 40px;
object-fit: cover;
border-radius: 50%;
}
.right .chat-container .notify-container {
width: 100%;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
}
.right .chat-container .notify-container .notify {
border-radius: 10px;
padding: 5px 10px;
background-color: #999999;
opacity: 0.9;
font-size: 12px;
color: white;
}
.right .input-container {
width: 100%;
height: 10%;
display: flex;
flex-direction: row;
justify-content: space-between;
background-color: blue;
font-size: 18px;
}
.right .input-container .input-content {
position: relative;
width: 85%;
background-color: white;
}
.right .input-container .input-content input {
border: 0;
padding: 10px;
width: 100%;
height: 100%;
box-sizing: border-box;
/* 去除input框外边框 */
outline: none;
font-size: 18px;
}
.right .input-container .input-content .num {
position: absolute;
right: 0;
top: 0;
width: 70px;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0.6), rgba(255, 255, 255, 1));
font-weight: bold;
color: #333333;
}
.right .input-container .input-content input::-webkit-input-placeholder {
font-size: 18px;
}
.right .input-container .send {
width: 15%;
display: flex;
justify-content: center;
align-items: center;
background-color: orange;
font-weight: bold;
}
</style>
</head>
<body>
<div class="chatroom">
<!--左侧-->
<div class="left">
<!--头像-->
<div class="icon-container">
<img src="https://i.niupic.com/images/2018/08/10/5yxS.jpg" />
</div>
<!--个人简介-->
<div class="self-container">
<div class="id">号码</div>
<div class="content">
<!--姓名-->
<div class="name">姓名</div>|
<!--性别-->
<div class="gender">男</div>|
<!--年龄-->
<div class="age">32岁</div>
</div>
</div>
<!--聊天室说明-->
<div class="note-container"></div>
</div>
<!--右侧-->
<div class="right">
<!--顶部固定导航-->
<div class="head">聊天室(<span id="count">0</span>)</div>
<!--聊天记录-->
<div class="chat-container">
</div>
<!--底部输入框-->
<div class="input-container">
<div class="input-content">
<input id="msg" autofocus="autofocus" value="" oninput="inputMessage()" placeholder="请输入聊天内容…" />
<div class="num">0/30</div>
</div>
<div class="send" onclick="send()">发送</div>
</div>
</div>
</div>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="http://wulv5.com/js/socket.io.min.js"></script>
<script>
// 建立连接
const socket = io.connect("/");
// 编号
let id = 0;
// 允许输入的最大字数
const maxInput = 30;
// 用户头像
let icon = 'https://i.niupic.com/images/2018/08/10/5yxS.jpg';
// 用户姓名
let name = '';
getName();
// 如果监听到socket消息,那么执行该回调函数,并得到广播消息
// 此处的message参数是后台广播的内容
socket.on("message", function(message) {
console.log(message)
let html = '';
// const container = document.getElementsByClassName("chat-container");
if(name == message.name) {
html = '<div class="message-self"><div class="message-container"><div class="message-content"><div class="name">' + message.name + '</div><div class="message">' + message.msg + '</div></div><div class="icon"><img src="' + icon + '" /></div></div></div>';
} else {
html = '<div class="message-other"><div class="message-container"><div class="icon"><img src="' + icon + '" /></div><div class="message-content"><div class="name">' + message.name + '</div><div class="message">' + message.msg + '</div></div></div></div>';
}
$(".chat-container").append(html);
scrollToBottom();
});
// 接收到系统通知
socket.on("joinNoticeSelf", function(message) {
$("#count").text(message.count);
id = message.id;
$(".id").text(message.id + '号');
});
// 接收到系统通知
socket.on("joinNoticeOther", function(message) {
console.log("joinNoticeOther:");
console.log(message);
$("#count").text(message.count);
const msg = {
name: message.name,
action: message.action
}
notify(msg);
});
// 断开连接回调事件
socket.on("disconnection", function(message) {
console.log(message);
$("#count").text(message.count);
const notifyMessage = {
name: message.name,
action: "退出了群聊"
};
notify(notifyMessage);
});
document.onkeydown = function(event) {
var e = event || window.event || arguments.callee.caller.arguments[0];
if(e && e.keyCode == 13) { // enter 键
send();
}
};
/**
* 发送系统通知
*
* @param {Object} message
*/
function notify(message) {
const notify = '<div class="notify-container"><div class="notify"><span class="name">' + message.name + '</span>' + message.action + '</div></div>';
$(".chat-container").append(notify);
scrollToBottom();
}
/**
* 固定滚动条到底部
*/
function scrollToBottom() {
$(".chat-container").scrollTop($(".chat-container")[0].scrollHeight);
}
/**
* 获取姓名
*/
function getName() {
const str = prompt("请输入你的名字", "");
if(str) {
name = str;
console.log(name)
$(".self-container .name").text(str);
const message = {
name: name
}
socket.emit("join", message);
} else {
getName();
}
}
/**
* 输入消息
*/
function inputMessage() {
const msg = $("#msg").val();
const length = $("#msg").val().length;
if(length > maxInput) {
$("#msg").val(msg.substr(0, maxInput));
$(".num").text(maxInput + '/' + maxInput);
} else {
const text = length + '/' + maxInput;
$(".num").text(text);
}
}
/**
* 发送消息
*/
function send() {
var msg = $("#msg").val();
if("" == name) {
getName();
} else {
if("" == msg) {
} else {
const message = {
id: id,
name: name,
msg: msg
};
// 通过socket发送消息
socket.send(message);
scrollToBottom();
$("#msg").val("");
$(".num").text('0/' + maxInput);
}
}
}
</script>
</body>
</html>