NodeJS聊天室

 

跟着教学视频了解到websocket和socket.io的通信方法之后,自己写了一个交互效果更好的聊天室。

 

▍小插曲

2019.1.24:今天在聊天室后台无意间看到了这样一段聊天,希望这位名叫luke所说的是假的,如果是真的,请相信,这世界上还有更好的人在等着你。

 

▍演示效果

 

▍实现过程(Windows系统)

1、在nodeJS中文网下载nodeJS客户端并安装;

2、在桌面(未知可自选)创建一个项目文件夹用于存放相关文件;

3、打开新建的文件夹,创建chatRoom.html文件和server.js文件;

4、打开命令行窗口,找到这个文件夹后,输入【npm i socket.io】,此时将在该文件夹中生成了一个新的文件夹,这是刚刚下载的socket.io相关依赖包;

5、将代码补充到chatRoom.html文件和server.js文件中;

6、打开命令行窗口,找到该项目文件夹后,输入【node 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"
	});
	// 可发送文本
	// response.end("hello world");

	// 可自动解析html
	// response.end("<h1>我是标题2</h1>");

	// 读取文件
	const html = fs.readFileSync("index.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.broadcast.emit("connection", {
	//		count: count,
	//		id: count
	//	});

	// 给自己发送上线信息
	//	socket.emit("connection", {
	//		count: count,
	//		id: totalCount
	//	});

	// 加入群聊
	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);
console.log('Server has started.\n')

 

▍chatRoom.html

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8">
	<title>蜗牛先生的聊天室</title>
	<style>
		* {
			margin: 0;
			padding: 0;
		}

		html {
			display: flex;
			justify-content: center;
			align-items: center;
			width: 100%;
			height: 100%;
			overflow: hidden;
			background-color: #d4f0fc;
			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);
			background-size: 100% 100%;
		}

		.chatroom {
			display: flex;
			width: 1000px;
			height: 700px;
			border-radius: 20px;
			overflow: hidden;
		}

		.left {
			position: relative;
			display: flex;
			flex-direction: column;
			align-content: center;
			width: 30%;
			height: 100%;
			background-color: #478291;
		}

		.icon-container {
			display: flex;
			justify-content: center;
			align-items: center;
			margin-top: 40px;
			height: 30%;
		}

		.icon-container img {
			border: 10px solid #333;
			width: 150px;
			height: 150px;
			object-fit: cover;
			border-radius: 50%;
		}

		.icon-container img:hover {
			animation: rotate 2s linear infinite forwards;
		}

		@keyframes rotate {
			from {
				transform: rotate(0);
			}

			to {
				transform: rotate(360deg);
			}
		}

		.self-container {
			display: flex;
			justify-content: center;
			align-items: center;
			height: 15%;
			line-height: 60px;
			font-size: 25px;
			font-weight: 700;
			color: #cadeea;
		}

		.function-container {
			display: flex;
			justify-content: flex-start;
			align-items: flex-start;
			flex-wrap: wrap;
			padding: 0 30px;
			color: #617c8f;
		}

		.function-item {
			margin: 5px;
			border: 3px solid #333;
			padding: 5px 10px;
			background: #fff;
			font-size: 14px;
		}

		.note-help {
			position: absolute;
			bottom: 20px;
			padding: 0 30px;
			font-size: 12px;
			color: #9cadad;
			text-align: center;
		}

		.right {
			width: 70%;
			height: 100%;
			background-color: #eee;
		}

		.head {
			display: flex;
			justify-content: center;
			align-items: center;
			height: 10%;
			width: 100%;
			background-color: white;
			font-size: 22px;
			font-weight: bold;
		}

		.chat-container {
			height: 80%;
			overflow-y: scroll;
			box-sizing: border-box;
		}

		.speaker-name {
			padding: 5px 0;
			font-size: 12px;
			color: #888888;
		}

		.message-self,
		.message-other {
			display: flex;
			flex-direction: row;
			flex-wrap: nowrap;
			padding: 10px;
			width: 100%;
			box-sizing: border-box;
		}

		.message-self {
			justify-content: flex-end;
		}

		.message-container {
			display: flex;
			flex-direction: row;
			max-width: 80%;
		}

		.message-self .message-content {
			padding-right: 10px;
		}

		.message-other .message-content {
			padding-left: 10px;
		}

		.message-self .message {
			background-color: blue;
			color: white;
		}

		.message-other .message {
			background-color: white;
			color: black;
		}

		.message-self .speaker-name {
			text-align: right;
		}

		.message-other .speaker-name {
			text-align: left;
		}

		.message {
			border-radius: 10px;
			padding: 10px;
		}

		.message-container .icon img {
			width: 40px;
			height: 40px;
			object-fit: cover;
			border-radius: 50%;
		}

		.message-table {
			border-collapse: collapse;
			border: 2px dashed #aaa;
		}

		.message-table-th {
			border-bottom: 2px dashed #aaa;
			padding: 5px 10px;
		}

		.message-table-td {
			padding: 5px 10px;
		}

		.notify-container {
			display: flex;
			justify-content: center;
			align-items: center;
			width: 100%;
			height: 50px;
		}

		.notify {
			border-radius: 10px;
			padding: 5px 10px;
			background-color: #ddd;
			opacity: 0.9;
			font-size: 12px;
			color: white;
		}

		.notify-name {
			color: blue;
		}

		.input-container {
			display: flex;
			flex-direction: row;
			justify-content: space-between;
			width: 100%;
			height: 10%;
			background-color: blue;
			font-size: 18px;
		}

		.input-content {
			position: relative;
			width: 85%;
			background-color: white;
		}

		.input-content input {
			border: 0;
			padding: 10px;
			width: 100%;
			height: 100%;
			box-sizing: border-box;
			/* 去除input框外边框  */
			outline: none;
			font-size: 18px;
		}

		.input-content .num {
			position: absolute;
			right: 0;
			top: 0;
			display: flex;
			justify-content: center;
			align-items: center;
			width: 70px;
			height: 100%;
			background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0.6), rgba(255, 255, 255, 1));
			font-weight: bold;
			color: #333333;
		}

		.input-content input::-webkit-input-placeholder {
			font-size: 18px;
		}

		.input-container .send {
			display: flex;
			justify-content: center;
			align-items: center;
			width: 15%;
			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>

			<!--聊天室说明-->
			<div class="function-container">
				<div class="function-item">尬聊模式</div>
				<div class="function-item">“讲个笑话”</div>
				<div class="function-item">“歇后语”</div>
				<div class="function-item">“顺口溜”</div>
				<div class="function-item">“北京天气”</div>
				<div class="function-item">“名人名言”</div>
				<div class="function-item">“静夜思”</div>
			</div>

			<div class="note-help">
				如果您有什么好的页面设计方案,请将您的设计稿发送至 tanabalu@qq.com ,非常感谢!
			</div>
		</div>

		<!--右侧-->
		<div class="right">
			<!--顶部固定导航-->
			<div class="head">聊天室(<span id="count">0</span>)</div>

			<!--聊天记录-->
			<div class="chat-container">
				<div class="message-other">
					<div class="message-container">
						<div class="icon">
							<img src="http://file06.16sucai.com/2016/0921/2b04bfeb965677fe8c2d5a4dbd292478.jpg" />
						</div>
						<div class="message-content">
							<div class="speaker-name">机器人</div>
							<div class="message">你好呀,小主人,欢迎来到TAchat。</div>
						</div>
					</div>
				</div>
				<div class="message-other">
					<div class="message-container">
						<div class="icon">
							<img src="http://file06.16sucai.com/2016/0921/2b04bfeb965677fe8c2d5a4dbd292478.jpg" />
						</div>
						<div class="message-content">
							<div class="speaker-name">机器人</div>
							<div class="message">
								<table class="message-table">
									<tr>
										<th class="message-table-th">您可尝试输入以下指令:</th>
									</tr>
									<tr>
										<td class="message-table-td">1、讲个笑话</td>
									</tr>
									<tr>
										<td class="message-table-td">2、歇后语</td>
									</tr>
									<tr>
										<td class="message-table-td">3、顺口溜</td>
									</tr>
									<tr>
										<td class="message-table-td">4、xx天气</td>
									</tr>
									<tr>
										<td class="message-table-td">5、名人名言</td>
									</tr>
									<tr>
										<td class="message-table-td">6、诗词</td>
									</tr>
									<tr>
										<td class="message-table-td">……</td>
									</tr>
								</table>
							</div>
						</div>
					</div>
				</div>
				<div class="message-other">
					<div class="message-container">
						<div class="icon">
							<img src="http://file06.16sucai.com/2016/0921/2b04bfeb965677fe8c2d5a4dbd292478.jpg" />
						</div>
						<div class="message-content">
							<div class="speaker-name">机器人</div>
							<div class="message">还可以邀请小伙伴打开本网址与您一起聊天呢!</div>
						</div>
					</div>
				</div>
			</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="https://cdn.bootcss.com/socket.io/2.3.0/socket.io.dev.js"></script>
	<!-- <script src="jquery.particleground.min.js"></script> -->
	<script>
		// 建立连接
		const socket = io.connect("/");

		// 编号
		let id = 0;

		// 允许输入的最大字数
		const maxInput = 30;

		// 用户头像
		const userIcon = 'https://i.niupic.com/images/2018/08/10/5yxS.jpg';

		// 机器人头像
		const robotIcon = 'http://file06.16sucai.com/2016/0921/2b04bfeb965677fe8c2d5a4dbd292478.jpg';

		// 用户姓名
		let name = '';

		getName();

		// 如果监听到socket消息,那么执行该回调函数,并得到广播消息
		// 此处的message参数是后台广播的内容
		socket.on("message", function (message) {
			console.log(message)
			let html = '';
			if (name === message.name) {
				html =
					'<div class="message-self"><div class="message-container"><div class="message-content"><div class="speaker-name">' +
					message.name + '</div><div class="message">' + message.msg +
					'</div></div><div class="icon"><img src="' + userIcon + '" /></div></div></div>';
			} else {
				html = '<div class="message-other"><div class="message-container"><div class="icon"><img src="' +
					userIcon + '" /></div><div class="message-content"><div class="speaker-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) {
			if (message.name && message.action) {
				const notify = '<div class="notify-container"><div class="notify"><span class="notify-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").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 getReply(msg) {
			$.ajax({
				url: "http://api.tianapi.com/txapi/robot/",
				data: {
					key: '762be789103e1ae7b65573f8d4fc0df6',
					question: msg,
				},
				success: function (res) {
					if (res.code === 200) {
						const newslist = res.newslist;
						for (let i = 0; i < newslist.length; i++) {
							const html =
								'<div class="message-other"><div class="message-container"><div class="icon"><img src="' +
								robotIcon +
								'" /></div><div class="message-content"><div class="speaker-name">机器人</div><div class="message">' +
								newslist[i].reply + '</div></div></div></div>';
							$(".chat-container").append(html);
						}
						scrollToBottom();
					}
				}
			});
		}

		/**
		 * 发送消息
		 */
		function send() {
			var msg = $("#msg").val();
			if (!name) {
				getName();
			} else if (msg) {
				const message = {
					id,
					name,
					msg,
				};
				// 通过socket发送消息
				socket.send(message);
				getReply(msg);
				$("#msg").val("");
				$(".num").text('0/' + maxInput);
			}
		}
	</script>

</body>

</html>

 

关注公众号:爱唱歌的蜗牛先生

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值