基于websockt实现的聊天室


任务

仿QQWeb即时聊天系统
一.功能要求
实现Web的点对点即时的文本消息聊天功能。
实现Web的表情的发送、接收和显示功能。
实现Web的图片的发送、接收和显示功能。
实现本地消息的存储,在离线的时候也能加载和查看历史消息;
要求使用WebSocket;


前期准备

客户端

websocket

websocket是实现服务器与客户端快速便捷连接,只需一次握手即可建立浏览器与服务器的通道持久协议 客户端可以主动给浏览器发送消息(传统HTTP不行)

HTML5已经提供了websocket的api,可以直接使用
连接的url是什么—>wensocket的服务端

流程:创建websocket(new)------->建立连接(open)------>向服务器发送消息(send)------>接收服务器的消息message------>(断开连接)

socket.io

Socket.io是一个WebSocket库

在使用前先在命令行中加载这些
npm install jquery
npm install socketio
npm install express

用管理员身份运行命令行才行,遇到了和上次一样的问题

浏览器与服务器的通信,用socket的emit和on方法即可

参数1:事件名
emit 参数2//可以理解为接收信息(监听到参数1后,触发参数2
on(参数1, 参数2)

//可以理解为发送信息(触发参数1,并且传递参数2
emit(参数1, 参数2)

css

  • position:fixed
  • div>p 与 div p
  • hover

jQuery

jQuery 极大地简化了 JavaScript 编程,由于之前对js有了解不再多加赘述,在此只涉及与课程设计相关的知识

jQuery 库是一个 JavaScript 文件,可以使用 HTML 的 <script> 标签引用它:

<script src="jquery-1.10.2.min.js"></script>
元素选取
/*
使用符号$选取html元素
*/
$("p") //选取所有<p>元素
$(".classs") //选取所有class="classs"的元素
$("#ids") //选取所有id="ids"的元素
操作
?增删改查
  • 获取:
    三个简单实用的用于 DOM 操作的 jQuery 方法:
    text() : 设置或返回所选元素的文本内容
    html() :设置或返回所选元素的内容(包括 HTML 标记)
    val() :设置或返回表单字段的值
    attr() :方法用于获取属性值。

    • eg:$(#idd).text()
  • append

  • empty

文件

js对文件的操作非常非常有限

事件方法
  • 页面中指定一个点击事件:

    $("p").click();
    
  • 隐藏元素
    可以使用 toggle() 方法来切换 hide() 和 show() 方法

    $("#hide").click(function(){
      $("p").hide();
    });
     
    $("#show").click(function(){
      $("p").show();
    });
    $("button").click(function(){
    	$("p").toggle();
    });
    
  • 鼠标移入,移出

    //入
    $("p").mouseenter(function(){
        $("p").css("background-color","yellow");
    });
    //出
    $("p").mouseleave(function(){
        $("p").css("background-color","gray");
    });
    
    
    
数组
  • 查找

    //获取下标为1的元素
    username.slice(1);
    //删除最后一个元素
    username.pop();
    //找出最后一个元素并修改
    usernames[usernames.length-1]=-1;
    
  • 循环

    var arr = [1, 2, 3, 4, 5];
    
    arr.forEach(function (item) {
        if (item === 3) {
            return;
        }
        console.log(item);
    });
    //上下两者一样
    arr.forEach(item=>{
    	 if (item === 3) {
            return;
        }
        console.log(item);
    });
    
    注意:forEach不改变原数组
    


服务端

node.js

之前课设安装过,直接用就行
node.js是什么:node.js是后台语言,是运行在服务端的JavaScript。

连接数据库

var mysql      = require('mysql');
var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'root',
  password : '123456',
  database : 'websocket'
  //自己创建数据库的名字!!
});
 
connection.connect();
 
connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
  if (error) throw error;
  console.log('The solution is: ', results[0].solution);
});

用法

//为指定事件添加一个监听器到监听器数组的尾部
addListener(event, listener)

//on 函数用于绑定,监听事件函数(为指定事件注册一个监听器
on(event, listener)

//emit 属性用于触发一个事件(按监听器的顺序执行执行每个监听器,如果事件有注册监听返回 true,否则返回 false
emit(event, [arg1], [arg2], [...])

//返回指定事件的监听器数量
listenerCount(emitter, event)

写的时候遇到的问题

app.js

1.io与socket

客户端与服务器建立链接会触发connection事件

io.on("connection",function(socket){
    //其他操作
});

socket.emit:触发当前用户(给当前用户发送消息
只有当前用户页面改变
io.emit:给所有用户发送(广播事件
所有用户页面改变


2.data
data可以理解为接收数据的结构体

socket.emit('send',{
            name:'zt',
            age: '18'
        })
 socket.on('send', data => {
       console.log(data)
     })

!!! 3.出现了很严重的问题
问题描述:只有新用户连接时,消息才会弹出

错误原因:逻辑错误
逻辑:服务器从客户端接收后就立刻返回给浏览器,所以需要服务器主动去发送消息
错误方法:

io.on('connection', function(socket){
 socket.on('send_app.js_text',function(data){
           /* 测试 :console.log(message); */
		   
		   //块作用域
		   let message = {
			   time:getNowTime(),
			   name:name,
			   text:data
		   }
		   console.log(message);
		   
    });
   socket.emit('send_message',message);
   //写在这里,逻辑变成有用户连接时才会send消息给浏览器
});

修改:

 socket.on('send_app.js_text',function(data){
           /* 测试 :console.log(message); */
		   
		   //块作用域
		   let message = {
			   time:getNowTime(),
			   name:name,
			   text:data
		   }
		   console.log(message);
		   io.emit('send_message',message);
		   //写在这里才是服务器主动给客户端发送消息
    });

4.问题描述:1 2 3 4用户,2退出但是列表去除的是4
原因:逻辑错误

socket.on('disconnect',function(data){
		//找到该用户并移出数组(删除用户)	
		for(i=0;i<usernames.length;i++){
			if(usernames[i] == name)
			usernames[i]=-1;
		}
		usernames.forEach(item=>{
			console.log(item);
		});
		//向所有用户发送离开信息
		io.emit('send_names',usernames);
		
	});

解决方法 利用socket.name

socket.on('disconnect',function(data){
		//找到该用户并移出数组(删除用户)	
		for(i=0;i<usernames.length;i++){
			if(usernames[i] == socket.name)
			usernames[i]=-1;
		}
		usernames.forEach(item=>{
			console.log(item);
		});
		//向所有用户发送离开信息
		io.emit('send_names',usernames);
		
	});

index.js

1.清空聊天框内容

其实很简单,只要$("#text").val(""); 就行,
但是尝试了remove和empty方法不行
开始还特别蠢的用了$("#text").val()=" "


2.let与var

ES6 可以使用 let 关键字来实现块级作用域。
let 声明的变量只在 let 命令所在的代码块 {} 内有效,在 {} 之外不能访问。
eg

var x = 10;
{ 
    var x = 2;
}
x
这里 x 为 2
var x = 10;
{ 
    let x = 2;
}
x
这里 x 为 10

3.参数引用

例如引用变量a要用${a}
在append后面加入html元素时使用 ` 符号 例:

$(".body-right").append(`
			<p style="text-align:center;">${item.time}</p>
			<p>用户${item.name}</p>
			<p>${item.text}</p>
			`);

但是在函数传递时又不用了 例:下述的n

scrollIntoView('.body-right');

function scrollIntoView(n) {
  $(n).children(':last').get(0).scrollIntoView(false);
  //$('.body-right')
}

4.在图片上传时遇到问题(label标签

input标签就提供了文件上传功能,开始还特别sb的想去用a标签去打开文件hhhhh

问题描述:点击input标签没有反应
原因:没点上

解决办法:将input标签伪造成图标,这里还要用到a标签去调用js,label标签确保能点上

<a href="javascript:;"  class="file">
	 <label for="file"></label>
 	 <input type="file" id="file" style="display: none;">
 	 //javascript:;是一个伪协议,作用是让a标签的超链接变成一个js方法的调用
</a>
//检测到使用了input上传文件后,对文件进行js操作
$('#file').on('change', function() {
	//文件操作
});

tip:label标签
label 元素不会向用户呈现任何特殊效果。如果在 label 元素内点击文本,就会触发此控件。就是说,当用户选择该标签时,浏览器就会自动将焦点转到和标签相关的表单控件上。

<label> 标签的 for 属性应当与相关元素的 id 属性相同。


5.在图片发送时遇到问题(

图片发送和消息发送其实是一个逻辑,但是图片消息的标签是img,而文字是p,所以需要设置一个type来判断输出的标签

		   data.forEach(item =>{
			$(".body-right").append(`
			<p style="text-align:center;color:grey">${item.time}</p>
			<p>用户${item.name}</p>
			`);
			if(item.type === "txt")
				$(".body-right").append(`<p>${item.text}</p>`);
			else
				$(".body-right").append(`<img src="${item.text}" alt="" />`);
		});

md删的时候删漏了个括号,找了八百年的错


6.emj表情框的放置

如何让emj的div悬浮在body中成为了一个问题

1.fixed

.emj{
	position: fixed;
	top: 50%;
	left: 16rem;
}

实现了悬浮,因为fix是独立一层,但是在放大缩小界面时会跑偏

在这里插入图片描述
查阅资料后
2.relative

//父样式中用yellow
.body-right{
	border: 1px solid yellow;
	float: right;
}

//子样式中用relative
.emj{
	position: relative;
}

但是会把body-right(黄色)的框挤出去
在这里插入图片描述

改了一圈发现最开始其实就是对的,我是sb,会跑的原因是因为top设定成百分比,如果设置为数值就不会跑

错的:
.emj{
	/* display: none; */
	position: fixed;
	top: 50%;
	left: 16rem;	
	width: 12.5rem;
	height:12.5rem;;
	border: 1px solid red;
}
改正:
.emj{
	/* display: none; */
	position: fixed;
	top: 400px;
	left: 16rem;	
	width: 12.5rem;
	height:12.5rem;;
	border: 1px solid red;
}

悬浮成功
在这里插入图片描述
用到的事件
框:hidden,show
鼠标:mouseenter,mouseleave

//鼠标移入表情包悬浮框显示
$('a.img').on('mouseenter', function() {
	$(".emj").show();
});
//鼠标移出,表情包悬浮框消失
$('div.emj').on('mouseleave', function() {
	$("div.emj").hide();
});

表情的选取

1.问题描述:emmm报错了,可能不能用this?

//图片触发
$("div.emj").on('click',function(){
	alert(this.attr("src"));
换用其他的选择器试试

2.问题描述:无论点哪个,出来的都是第一个表情????
推测是选取元素出现了问题

$("div.emj").on('click',function(){
	alert($("img").attr("src"));
因为img元素都相同,所以无法分辨,可以换用id,但是这样一来每一个id都要绑定一个click事件,会很麻烦。试着用函数或者其他方法解决

用this就解决了
(操!this没有加括号所以报错,我还以为是this不能用,找了一大圈资料 操! 白给!

$("div.emj img").on('click',function(){
	alert($(this).attr("src"));
});

连接数据库,存储信息

数据库连接

let insertData = (table,datas,callback)=>{
  var fields='';
  var values='';
  for( var k in datas){
      fields+=k+',';
      values=values+"'"+datas[k]+"',"
  }
  fields=fields.slice(0,-1);
  values=values.slice(0,-1);
  console.log(fields,values);
  var sql="INSERT INTO "+table+'('+fields+') VALUES('+values+')';
  connection.query(sql,callback);
}

!!!!!!!!感天动地,存进来了
在这里插入图片描述

但是在传历史信息的时候出现问题,测试发现问题出现在 socket.emit这一步,应该是是res中多了一个数据库的主键id,而message中没有,但是id又不能重复,所以要使用一个数去记录id并传值

在这里插入图片描述emmmm后面发现其实是调用历史信息的数组和发送信息冲突了,干脆把数组取消,全部用成数据库

db.insertData('websocket', message, (e, r) => {
		       //测试
			   console.log('消息存入成功')
			   console.log(message); 
		   })
io.emit('send_message',message);
socket.on('send_message', function(data) {
	/* 测试 :alert(data); */
		$(".body-right").append(`
			<p style="text-align:center;color:grey">${data.time}</p>
			<p>用户${data.name}</p>
			`);
		if (data.type === "txt")
			$(".body-right").append(`<p>${data.text}</p>`);
		else if (data.type == "img")
			$(".body-right").append(`<img src="${data.text}" height=200px
	width=200px alt="" />`);
		else
			$(".body-right").append(`<img src="${data.text}" />`);
	scrollIntoView('.body-right');
});

调用数据库信息

问题描述:1用户发送的消息 2用户却看不到
emmm很离谱的原因,可能是因为图片文件太大(五十多万长的base64编码),所以数据库卡bug了,所以这里试着存储文件的地址而不是图片本身(但是目前还没能实现
c,原来,js不能获取.的文件路径,怪不得改了好久都不行。 js文件操作好坑,

ps:不过老师还提供了两个思路,一个是换用可以专门存储图片的数据库。还有一个是数据库中有一个专门存储这种的数据类型LONGBLOB 或者longtext

$('#file').on('change', function() {
	var file = this.files[0]
	//需要把这个文件发送到服务器,借助于H5新增的fileReader
	var fr = new FileReader()
	fr.readAsDataURL(file);
	fr.onload = function() {
		/* 测试:alert(fr.result); */
		socket.emit('send_app.js_text', {
		 name: name,
			text: fr.result,
			type: "img"
		});
	}
});

使用数组messages去记录历史信息并且下载

//加载历史消息
function initMessage(socket) {
    db.selectAll('select * from websocket order by id asc', (e, res) => {
        for (var i = 0; i < res.length; i++) {
			socket.emit('send_message', res[i]);	
			//将历史消息加入messages中,便于下载

在这里插入图片描述
终于成功了,改死我了


文件

本来想用js去实现本地消息的存储,但是查阅资料使用ActiveXObject 后会报错 ActiveXObject is not defined,很坑,是因为只有ie浏览器能用 ActiveXObjec

后面在服务器上实现了文件的下载:参考文章

	 socket.on('download',function(){
		 console.log("开始下载"); 
		const fs = require("fs");
		messages.forEach(item=>{
			fs.appendFileSync("test.txt", "用户"+item.name+":\r\n"+item.text+"\r\n\r\n");
			let data = fs.readFileSync("test.txt", "utf8");
			console.log(data); 
			})
		});

动态生成的DOM不会触发onclick事件

好啊,好,找了一晚上的错,原来是这样

$('a.li').on('click',function(){
	alert($(this);
});

noclick等事件不能绑定dom动态元素,只能绑定静态元素

$('.card1').on('click',function(){
	alert($(this);
});

但是这样就不能选择出每个用户,而是整个用户列表

查到资料大佬的博客后修改

提过父元素card1,成功绑定了动态dmo的a标签
$('.card1').on('click','a.li',function(){
	alert($(this).attr('id'));
});
float

刚开始把名字和内容没有放在一个div里,会造成重叠,后面放到了一个div里面

$(".body-right1").append(`
				<p style="text-align:center;color:grey">${data.time}</p>`);
		if (data.type === "txt")
				$(".body-right1").append(`
				<div class="right">
				<p style="text-align:${direction} ">用户${data.save_name}</p>
				<p>${data.text}</p>
				</div>`);

不清除浮动的后果hhh
在这里插入图片描述
修改后

.right{
	/*消息排版会乱掉 
	1.float: right;
	2.position:absolute;
	    right:50px; 
		*/
	float: right;
	 clear:both;
}

记录

day1完成的:

前端的页面代码
初步实现了用户加入聊天室时更新左侧用户列表,
初步实现发送消息,以及发送消息时提示时间

index.html

<!DOCTYPE html>
<html >
	<head>
		<meta charset="UTF-8">
		<title>聊天室</title>
		<link rel="stylesheet" type="text/css" href="index.css"> 
		<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
	</head>
	<body>
		<div class="box">
			<div class="head">
				聊天室
			</div>
			<div class="body">
				<div class="body-left">
					<div class="card">
						<h3>公告栏</h3>
						<p>请文明发言</p>
						<p class="p1">欢迎加入聊天,用户</p>
					</div>
					<h4>聊天室成员</h4>
					<div class="card1">
					<ul>
					</ul>
					</div>
				</div>
				<div class="body-right">
				
				</div>
			</div>
			<div class="foot">
				<div class="foot-tool">
					<img src="img/emj.png" />
					<img src="img/img.png" />
				</div>
					
				<div class="foot-text">
					<textarea rows="6" cols="200" id="text">
					</textarea>
				</div>
				<div class="foot-send">
					<button type="button" id="button">发 送</button>
				</div>
			</div>
		</div>
		<script src="./socket.io/socket.io.js"></script>
		<script src="./js/index.js"></script>

		
	</body>
</html>

index.css

* {
	box-sizing: border-box;
	/* background-color: darkgrey; */
}

/* 聊天框整体 */
.box {
	display: block;
	border: 1px solid black;
	margin: 5rem 15rem;
	width: 60rem;
	height: 40rem;
	background-color: aliceblue;
}


.head{
	border: 1px solid skyblue;
	background-color: #87CEEB;
	height: 5%;
	text-align: center;
}

/* 对话框 */
.body{
	background-color: #F0F8FF;
	border: 1px solid blueviolet;
	height: 70%;
}
.body-left{
	background-color: white;
	border: 1px solid blue;
	float: left;
	width: 20%;
	height: 100%;
}
.body-right{
	border: 1px solid blue;
	float: right;
	width: 80%;
	height: 100%;
	overflow: scroll;
}
.card{
	height: 30%;
	border: 1px solid black;
}
.card1{
	height: 55%;
	border: 1px solid black;
	overflow: scroll;
}

/* 输入框 */
.foot{
	background-color: whitesmoke;
	border: 1px solid blueviolet;
	height: 25%;
}
.foot-tool{
	border: 1px solid black;
	height: 15%
	width: 100%;
	
}
.foot-text{
	border: 1px solid black;
	height: 50%;
	width: 100%;
	overflow: hidden;
}
.foot-send{
	border: 1px solid brown;
	height: 20%;
	width: 100%;
	overflow: hidden;
}


/* 清除默认格式 */
ul{
	
	 list-style-type: none;
	  margin: 0;
	  padding: 0.3125rem;
}

/* 设置按钮大小 */
button{
	background-color: dodgerblue;
	padding: 0.25rem 2.5rem;
	float: right;
}

/* 当鼠标移点击页面时自动对焦到第一行 */
textarea{
	
}

index.js

/* 
	聊天室的功能
*/
/* 1.连接服务器 */
var socket = io();

/* 2.用户信息 */
//创建全局变量
var name;

// 接收服务器创建的用户
socket.on('send_name', function(data) {
	name = data;
	$("p.p1").append(data);
});

//接收服务器所有用户的信息
socket.on('send_names', function(data) {
	/*测试: alert(data); */
	//统计聊天室成员
	data.forEach(item =>{
		$("ul").append("<li>用户"+item+"在线<li>");
	});
});


//接收服务器销毁用户信息
	//数组清空
	
	//name=0

/* 3.用户发送消息 */
//用户向服务器发送
$("#button").click(function() {	
	var text = $("#text").val();
	/* 测试:alert(text); */
	//向服务器发送信息
	socket.emit('send_app.js_text', text);
	//发送后内容清空
	$("#text").val("");
});
//接收服务器发送的消息
socket.on('send_message',function(data){
           /* 测试 :alert(data); */
		   //避免重复
		   $(".body-right").empty();
		   //循环输出数组
		   data.forEach(item =>{
			$(".body-right").append(`
			<p style="text-align:center;">${item.time}</p>
			<p>用户${item.name}</p>
			<p>${item.text}</p>
			`);
			
		   });
    });

app.js

const { data } = require('jquery');
// 通过express创建了http服务器
var app = require('express')();
var http = require('http').Server(app);//httpServer要绑定的服务器
var io = require('socket.io')(http);

//Express中static方法可以处理静态资源
//将public目录设置为静态资源目录
app.use(require('express').static('public'))
app.get('/', function(req, res){
  res.redirect('index.html')
});

/*获取当前时间*/
function getNowTime() {
    var date = new Date();
    //年 getFullYear():四位数字返回年份
    var year = date.getFullYear();  //getFullYear()代替getYear()
    //月 getMonth():0 ~ 11
    var month = date.getMonth() + 1;
    //日 getDate():(1 ~ 31)
    var day = date.getDate();
    //时 getHours():(0 ~ 23)
    var hour = date.getHours();
    //分 getMinutes(): (0 ~ 59)
    var minute = date.getMinutes();
    //秒 getSeconds():(0 ~ 59)
    var second = date.getSeconds();

    var time = ' ' + year + '-' + addZero(month) + '-' + addZero(day) + ' ' + addZero(hour) + ':' + addZero(minute) + ':' + addZero(second);
    return time;
}

function addZero(s) {
    return s < 10 ? ('0' + s) : s;
}


/* 定义全局变量 */

//用户名
var name = 0;
//总用户
var usernames = [];
//消息记录
var messages =[];


//监听了用户的连接事件
io.on('connection', function(socket){
	/* 2.用户信息 */
	//创建用户
	name = name+1;
	//将该用户加入登录用户中
	usernames.push(name);
	// 向浏览器发送该用户
	socket.emit('send_name',name);
    // 向浏览器发送所有用户
    socket.emit('send_names',usernames);
	
	/* 3.用户发送消息 */
	// 接收浏览器信息
    socket.on('send_app.js_text',function(data){
           /* 测试 :console.log(message); */
		   
		   //块作用域
		   let message = {
			   time:getNowTime(),
			   name:name,
			   text:data
		   }
		   messages.push(message)
		   console.log(messages);
		   io.emit('send_message',messages);
    });
	
});

//监听用户断开事件
	//用户数--
	
	//向浏览器发送信息

/*  */

//指定端口号为3000
http.listen(3000, function(){
  console.log('listening on *:3000');
});

day2完成的:

完善了用户断开连接的逻辑(用户离开时io消息,用户列表更新)
新增了上传图片功能

index.html

<!DOCTYPE html>
<html >
	<head>
		<meta charset="UTF-8">
		<title>聊天室</title>
		<link rel="stylesheet" type="text/css" href="index.css"> 
		<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
	</head>
	<body>
		<div class="box">
			<div class="head">
				聊天室
			</div>
			<div class="body">
				<div class="body-left">
					<div class="card">
						<h3>公告栏</h3>
						<p class="p1">欢迎加入聊天,用户</p>
					</div>
					<h4>聊天室成员</h4>
					<div class="card1">
					<ul>
					</ul>
					</div>
				</div>
				<div class="body-right">
				
				</div>
			</div>
			<div class="foot">
				<div class="foot-tool">
					<img  src="img/emj.png" />
					<a href="javascript:;"  class="file">
					  <label for="file"></label>
					  <input type="file" id="file" style="display: none;">
					</a>
					<!-- <img id="file" src="img/img.png" /> -->
					<!-- <input type="file"> -->
				</div>
					
				<div class="foot-text">
					<textarea rows="6" cols="200" id="text">
					</textarea>
				</div>
				<div class="foot-send">
					<button type="button" id="button">发 送</button>
				</div>
			</div>
		</div>
		<script src="./socket.io/socket.io.js"></script>
		<script src="./js/index.js"></script>
		

		
	</body>
</html>

index.css

* {
	box-sizing: border-box;
	/* background-color: darkgrey; */
}

/* 聊天框整体 */
.box {
	display: block;
	border: 1px solid black;
	margin: 5rem 15rem;
	width: 60rem;
	height: 40rem;
	background-color: aliceblue;
}


.head{
	border: 1px solid skyblue;
	background-color: #87CEEB;
	height: 5%;
	text-align: center;
}

/* 对话框 */
.body{
	background-color: #F0F8FF;
	border: 1px solid blueviolet;
	height: 70%;
}
.body-left{
	background-color: white;
	border: 1px solid blue;
	float: left;
	width: 20%;
	height: 100%;
}
.body-right{
	border: 1px solid blue;
	float: right;
	width: 80%;
	height: 100%;
	overflow: scroll;
}
/* 利用css给连接伪造一个图片 */
.foot .foot-tool .file {
  display: inline-block;
  vertical-align: middle;
  width: 40px;
  height: 45px;
  background: url('img/img.png') no-repeat ;
}
.foot .foot-tool .file label {
  width: 100%;
  height: 100%;
  display: block;
}
.card{
	height: 30%;
	border: 1px solid black;
}
.card1{
	height: 55%;
	border: 1px solid black;
	overflow: scroll;
}

/* 输入框 */
.foot{
	background-color: whitesmoke;
	border: 1px solid blueviolet;
	height: 25%;
}
.foot-tool{
	border: 1px solid black;
	height: 15%
	width: 100%;
	
}
.foot-text{
	border: 1px solid black;
	height: 50%;
	width: 100%;
	overflow: hidden;
}
.foot-send{
	border: 1px solid brown;
	height: 20%;
	width: 100%;
	overflow: hidden;
}


/* 清除默认格式 */
ul{
	
	 list-style-type: none;
	  margin: 0;
	  padding: 0.3125rem;
}

/* 设置按钮大小 */
button{
	background-color: dodgerblue;
	padding: 0.25rem 2.5rem;
	float: right;
}

/* 当鼠标移点击页面时自动对焦到第一行 */
textarea{
	
}

index.js

/* 
	聊天室的功能
	
	1.连接服务器 
	
	2.用户信息 
	//创建用户 (服务器创建用户,发送给该页面
	//销毁用户  (服务器销毁用户,发送给该页面
	
	
	3.用户发送消息 
	//个人用户向服务器发送
	//浏览器io给所有用户
	
	
*/
/* 1.连接服务器 */
var socket = io();

//当前元素(最近一条消息)底部滚动到可视区
function scrollIntoView(n) {
  $(n).children(':last').get(0).scrollIntoView(false);
}

/* 2.用户信息 */
//创建全局变量
var name;
//接收服务器创建的用户
socket.on('send_name', function(data) {
	$("p.p1").empty();
	name = data;
	$("p.p1").append(`
	<p>请文明发言</p>
	<p class="p1">欢迎加入聊天,用户${data}</p>
	`);
});
//接收服务器销毁的用户,并且在.body-right输出
socket.on('remove_names', function(data) {
	$(".body-right").append(`<p style="text-align:center;color:grey">用户${data}偷偷离开了聊天室</p>`);
	scrollIntoView('.body-right');
});
//在.body-left输出所有用户的信息
socket.on('send_names', function(data) {
	//先清空
	$("ul").empty();
	/*测试: alert(data); */
	//统计聊天室成员
	data.forEach(item =>{
		if(item>0)
		$("ul").append("<li>用户"+item+"在线<li>");
	});
	scrollIntoView('.body-left');
});


/* 3.用户发送消息 */

//用户向服务器发送消息
$("#button").click(function() {	
	var text = $("#text").val();
	/* 测试:alert(text); */
	//向服务器发送文字信息,type为txt
	socket.emit('send_app.js_text', {
		name:name,
		text:text,
		type:"txt"
	});
	//发送后内容清空
	$("#text").val("");
});
//用户向服务器发送图片消息,type为img
$('#file').on('change', function () {
  var file = this.files[0]
  //需要把这个文件发送到服务器,借助于H5新增的fileReader
  var fr = new FileReader()
  fr.readAsDataURL(file)
  fr.onload = function () {
	  alert(fr.result);
	  socket.emit('send_app.js_text', {
		  name:name,
		  text:fr.result,
		  type:"img"
	  });
  }
})

//接收服务器发送的消息
socket.on('send_message',function(data){
           /* 测试 :alert(data); */
		   //避免重复
		   $(".body-right").empty();
		   //循环输出数组
		   data.forEach(item =>{
			$(".body-right").append(`
			<p style="text-align:center;color:grey">${item.time}</p>
			<p>用户${item.name}</p>
			`);
			if(item.type === "txt")
				$(".body-right").append(`<p>${item.text}</p>`);
			else
				$(".body-right").append(`<img src="${item.text}" alt="" />`);
		});
		scrollIntoView('.body-right');
    });



app.js

const { data } = require('jquery');
// 通过express创建了http服务器
var app = require('express')();
var http = require('http').Server(app);//httpServer要绑定的服务器
var io = require('socket.io')(http);

//Express中static方法可以处理静态资源
//将public目录设置为静态资源目录
app.use(require('express').static('public'))
app.get('/', function(req, res){
  res.redirect('index.html')
});

/*获取当前时间*/
function getNowTime() {
    var date = new Date();
    //年 getFullYear():四位数字返回年份
    var year = date.getFullYear();  //getFullYear()代替getYear()
    //月 getMonth():0 ~ 11
    var month = date.getMonth() + 1;
    //日 getDate():(1 ~ 31)
    var day = date.getDate();
    //时 getHours():(0 ~ 23)
    var hour = date.getHours();
    //分 getMinutes(): (0 ~ 59)
    var minute = date.getMinutes();
    //秒 getSeconds():(0 ~ 59)
    var second = date.getSeconds();

    var time = ' ' + year + '-' + addZero(month) + '-' + addZero(day) + ' ' + addZero(hour) + ':' + addZero(minute) + ':' + addZero(second);
    return time;
}

function addZero(s) {
    return s < 10 ? ('0' + s) : s;
}


/* 定义全局变量 */

//用户名
var name = 0;
//总用户
var usernames = [];
//消息记录
var messages =[];


//监听了用户的连接事件
io.on('connection', function(socket){
	/* 2.用户信息 */
	//创建用户
	name = name+1;
	socket.name = name;
	//将该用户加入登录用户中
	usernames.push(name);
	// 向浏览器发送该用户
	socket.emit('send_name',name);
    // 向所有用户发送所有用户
    io.emit('send_names',usernames);
	
	/* 3.用户发送消息 */
	// 接收浏览器信息
    socket.on('send_app.js_text',function(data){
           /* 测试 :console.log(message); */
		   
		   //块作用域
		   let message = {
			   time:getNowTime(),
			   name:data.name,
			   text:data.text,
			   //通过type来区别信息
			   type:data.type
		   }
		   messages.push(message)
		   console.log(messages);
		   io.emit('send_message',messages);
    });
	
	//监听某位用户断开连接事件(自带功能,不需要浏览器emit)
	socket.on('disconnect',function(data){
		//找到该用户并移出数组(删除用户)	
		for(i=0;i<usernames.length;i++){
			if(usernames[i] == socket.name)
			usernames[i]=-1;
		}
		/*	测试
		usernames.forEach(item=>{
			console.log(item);
		}); 	*/
		//向所有用户发送离开信息
		io.emit('send_names',usernames);
		io.emit('remove_names',socket.name);
		
	});
		
	
});



/*  */

//指定端口号为3000
http.listen(3000, function(){
  console.log('listening on *:3000');
});


day3

完成了表情的发送

index.html

<!DOCTYPE html>
<html >
	<head>
		<meta charset="UTF-8">
		<title>聊天室</title>
		<link rel="stylesheet" type="text/css" href="index.css"> 
		<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
	</head>
	<body>
		<div class="box">
			
			<div class="head">
				聊天室
			</div>

			<div class="body">
				<!-- 用户信息栏 -->
				<div class="body-left">
					<div class="card">
						<h3>公告栏</h3>
						<p class="p1">欢迎加入聊天,用户</p>
					</div>
					<h4>聊天室成员</h4>
					<div class="card1">
						<ul>
						</ul>
					</div>		
				</div>
				<!-- 聊天信息框 -->
				<div class="body-right">
				
				</div>
			</div>
			<!-- 表情框,初始为隐藏 -->
			<div class="emj">
				<div> <img src="emj/1.png" id="1"/> </div>
				<div> <img src="emj/2.png" id="2"/> </div>
				<div> <img src="emj/3.png" /> </div>
				<div> <img src="emj/4.png" /> </div>
				<div> <img src="emj/5.png" /> </div>
				<div> <img src="emj/6.png" /> </div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
			</div>
			<div class="foot">
				<div class="foot-tool">
					<a href="javascript:;" class="img"></a>
					<a href="javascript:;"  class="file">
					  <label for="file"></label>
					  <input type="file" id="file" style="display: none;">
					</a>
					<!-- <img id="file" src="img/img.png" /> -->
					<!-- <input type="file"> -->
				</div>
					
				<div class="foot-text">
					<textarea rows="6" cols="200" id="text">
					</textarea>
				</div>
				<div class="foot-send">
					<button type="button" id="button">发 送</button>
				</div>
			</div>
			
		</div>
		<script src="./socket.io/socket.io.js"></script>
		<script src="./js/index.js"></script>
		

		
	</body>
</html>

index.css

* {
	box-sizing: border-box;
	/* background-color: darkgrey; */
}

/* 聊天框整体 */
.box {
	display: block;
	border: 1px solid black;
	margin: 5rem 15rem;
	width: 60rem;
	height: 40rem;
	background-color: aliceblue;
}


.head{
	border: 1px solid skyblue;
	background-color: #87CEEB;
	height: 5%;
	text-align: center;
}

/* 对话框 */
.body{
	/* 悬浮emj表情  父元素*/
	position: relative;
	
	background-color: #F0F8FF;
	border: 1px solid blueviolet;
	height: 70%;
}
.body-left{
	background-color: white;
	border: 1px solid green;
	float: left;
	width: 20%;
	height: 100%;
}
.body-right{
	border: 1px solid yellow;
	float: right;
	width: 80%;
	height: 100%;
	overflow: scroll;
}
.card{
	height: 30%;
	border: 1px solid black;
}
.card1{
	height: 55%;
	border: 1px solid black;
	overflow: scroll;
}

/* 输入框 */
.foot{
	background-color: whitesmoke;
	border: 1px solid blueviolet;
	height: 25%;
}
.foot-tool{
	border: 1px solid black;
	height: 15%
	width: 100%;
	
}
.foot-text{
	border: 1px solid black;
	height: 50%;
	width: 100%;
	overflow: hidden;
}
.foot-send{
	border: 1px solid brown;
	height: 20%;
	width: 100%;
	overflow: hidden;
}


/* 清除默认格式 */
ul{
	
	 list-style-type: none;
	  margin: 0;
	  padding: 0.3125rem;
}

/* 设置按钮大小 */
button{
	background-color: dodgerblue;
	padding: 0.25rem 2.5rem;
	float: right;
}

/* 利用css给连接伪造一个图片 */
.foot .foot-tool .file {
  display: inline-block;
  vertical-align: middle;
  width: 40px;
  height: 45px;
  background: url('img/img.png') no-repeat ;
}
.foot .foot-tool .img {
  display: inline-block;
  vertical-align: middle;
  width: 40px;
  height: 45px;
  background: url('img/emj.png') no-repeat ;
}

.foot .foot-tool .file label {
  width: 100%;
  height: 100%;
  display: block;
}

/* 表情框 */
.emj{
	/* display: none; */
	display: grid;
	grid-gap: 1px;
	grid-template-columns: auto auto auto auto;
	position: fixed;
	top: 350px;
	left: 16rem;	
	width: 12.5rem;
	height:12.5rem;
	border: 1px solid grey;
	background-color: gainsboro;
}
/* 规定网格大小 */
.emj > div{
	width: 3rem;
	height: 3rem;
	
}
/* 规定图片大小 */
div.emj img{
	width: 2.7rem;
	height: 2.7rem
}
/* 图片选择效果 */
div.emj img:hover{
	border: 1px solid grey;
	width: 3rem;
	height: 3rem
}

/* 当鼠标移点击页面时自动对焦到第一行 */
textarea{
	
}

index.js

/* 
	聊天室的功能
	
	1.连接服务器 
	
	2.用户信息 
	//创建用户 (服务器创建用户,发送给该页面
	//销毁用户  (服务器销毁用户,发送给该页面
	
	
	3.用户发送消息 
	//个人用户向服务器发送
	//浏览器io给所有用户
	
	
*/
/* 1.连接服务器 */
var socket = io();
/* if(socket===null) */
//隐藏表情框
$("div.emj").hide();


//当前元素(最近一条消息)底部滚动到可视区
function scrollIntoView(n) {
	$(n).children(':last').get(0).scrollIntoView(false);
}

/* 2.用户信息 */
//创建全局变量
var name;
//接收服务器创建的用户
socket.on('send_name', function(data) {
	$("p.p1").empty();
	name = data;
	$("p.p1").append(`
	<p>请文明发言</p>
	<p class="p1">欢迎加入聊天,用户${data}</p>
	`);
});
//接收服务器销毁的用户,并且在.body-right输出
socket.on('remove_names', function(data) {
	$(".body-right").append(`<p style="text-align:center;color:grey">用户${data}偷偷离开了聊天室</p>`);
	scrollIntoView('.body-right');
});
//在.body-left输出所有用户的信息
socket.on('send_names', function(data) {
	//先清空
	$("ul").empty();
	/*测试: alert(data); */
	//统计聊天室成员
	data.forEach(item => {
		if (item > 0)
			$("ul").append("<li>用户" + item + "在线<li>");
	});
	scrollIntoView('.body-left');
});


/* 3.用户发送消息 */

/*
 用户向服务器发送文字消息 
 */
$("#button").click(function() {
	var text = $("#text").val();
	/* 测试:alert(text); */
	//向服务器发送文字信息,type为txt
	socket.emit('send_app.js_text', {
		name: name,
		text: text,
		type: "txt"
	});
	//发送后内容清空
	$("#text").val("");
});
/* 
用户向服务器发送图片消息,type为img 
*/
$('#file').on('change', function() {
	var file = this.files[0]
	//需要把这个文件发送到服务器,借助于H5新增的fileReader
	var fr = new FileReader()
	fr.readAsDataURL(file)
	fr.onload = function() {
		/* 测试:alert(fr.result); */
		socket.emit('send_app.js_text', {
		 name: name,
			text: fr.result,
			type: "img"
		});
	}
});
/* 
用户向服务器发送表情包消息,type为emj
 */
//表情选取
	//鼠标移入表情包悬浮框显示
	$('a.img').on('mouseenter', function() {
		$(".emj").show();
	});
	//鼠标移出,表情包悬浮框消失
	$('div.emj').on('mouseleave', function() {
		$("div.emj").hide();
	});
//点击表情获取src属性
$("div.emj img").on('click',function(){
	/* 测试: alert($(this).attr("src")); */
	//加入聊天框
	socket.emit('send_app.js_text', {
	 name: name,
		text: $(this).attr("src"),
		type: "emj"
	});
	
});
	
/* 接收服务器发送的消息 */
socket.on('send_message', function(data) {
	/* 测试 :alert(data); */
	//避免重复
	$(".body-right").empty();
	//循环输出数组
	data.forEach(item => {
		$(".body-right").append(`
			<p style="text-align:center;color:grey">${item.time}</p>
			<p>用户${item.name}</p>
			`);
		if (item.type === "txt")
			$(".body-right").append(`<p>${item.text}</p>`);
		else if (item.type == "img")
			$(".body-right").append(`<img src="${item.text}" height=200px
	width=200px alt="" />`);
		else
			$(".body-right").append(`<img src="${item.text}" />`);
	});
	scrollIntoView('.body-right');
});

/* 下载消息 */
/* socket.on('download', function(data) {
	var 
}); */

app.js

const { data } = require('jquery');
// 通过express创建了http服务器
var app = require('express')();
var http = require('http').Server(app);//httpServer要绑定的服务器
var io = require('socket.io')(http);

//Express中static方法可以处理静态资源
//将public目录设置为静态资源目录
app.use(require('express').static('public'))
app.get('/', function(req, res){
  res.redirect('index.html')
});

/*获取当前时间*/
function getNowTime() {
    var date = new Date();
    //年 getFullYear():四位数字返回年份
    var year = date.getFullYear();  //getFullYear()代替getYear()
    //月 getMonth():0 ~ 11
    var month = date.getMonth() + 1;
    //日 getDate():(1 ~ 31)
    var day = date.getDate();
    //时 getHours():(0 ~ 23)
    var hour = date.getHours();
    //分 getMinutes(): (0 ~ 59)
    var minute = date.getMinutes();
    //秒 getSeconds():(0 ~ 59)
    var second = date.getSeconds();

    var time = ' ' + year + '-' + addZero(month) + '-' + addZero(day) + ' ' + addZero(hour) + ':' + addZero(minute) + ':' + addZero(second);
    return time;
}

function addZero(s) {
    return s < 10 ? ('0' + s) : s;
}


/* 定义全局变量 */

//用户名
var name = 0;
//总用户
var usernames = [];
//消息记录
var messages =[];


//监听了用户的连接事件
io.on('connection', function(socket){
	/* 2.用户信息 */
	//创建用户
	name = name+1;
	socket.name = name;
	//将该用户加入登录用户中
	usernames.push(name);
	// 向浏览器发送该用户
	socket.emit('send_name',name);
    // 向所有用户发送所有用户
    io.emit('send_names',usernames);
	
	/* 3.用户发送消息 */
	// 接收浏览器信息
    socket.on('send_app.js_text',function(data){
           /* 测试 :console.log(message); */
		   
		   //块作用域
		   let message = {
			   time:getNowTime(),
			   name:data.name,
			   text:data.text,
			   //通过type来区别信息
			   type:data.type
		   }
		   messages.push(message)
		   console.log(messages);
		   io.emit('send_message',messages);
    });
	
	//监听某位用户断开连接事件(自带功能,不需要浏览器emit)
	socket.on('disconnect',function(data){
		//找到该用户并移出数组(删除用户)	
		for(i=0;i<usernames.length;i++){
			if(usernames[i] == socket.name)
			usernames[i]=-1;
		}
		/*	测试
		usernames.forEach(item=>{
			console.log(item);
		}); 	*/
		//向所有用户发送离开信息
		io.emit('send_names',usernames);
		io.emit('remove_names',socket.name);
		/* //下载消息
		socket.emit('download',messages);
		messages */
	});
		
	
});



/*  */

//指定端口号为3000
http.listen(3000, function(){
  console.log('listening on *:3000');
});

day4

把数据库连上了,以及消息存储到本地(但是图片的存储存在问题,老师说可以通过mongodb或者存路径
messages数组变成了存储历史消息并放入txt
导入信息则完全交给了数据库

index.html

<!DOCTYPE html>
<html >
	<head>
		<meta charset="UTF-8">
		<title>聊天室</title>
		<link rel="stylesheet" type="text/css" href="index.css"> 
		<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
	</head>
	<body>
		<div class="box">
			
			<div class="head">
				聊天室
			</div>

			<div class="body">
				<!-- 用户信息栏 -->
				<div class="body-left">
					<div class="card">
						<h3>公告栏</h3>
						<p class="p1">欢迎加入聊天,用户</p>
					</div>
					<h4>聊天室成员</h4>
					<div class="card1">
						<ul>
						</ul>
					</div>		
				</div>
				<!-- 聊天信息框 -->
				<div class="body-right">
				
				</div>
			</div>
			<!-- 表情框,初始为隐藏 -->
			<div class="emj">
				<div> <img src="emj/1.png" id="1"/> </div>
				<div> <img src="emj/2.png" id="2"/> </div>
				<div> <img src="emj/3.png" /> </div>
				<div> <img src="emj/4.png" /> </div>
				<div> <img src="emj/5.png" /> </div>
				<div> <img src="emj/6.png" /> </div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
			</div>
			<div class="foot">
				<div class="foot-tool">
					<a href="javascript:;" class="img"></a>
					<a href="javascript:;"  class="file">
					  <label for="file"></label>
					  <input type="file" id="file" style="display: none;">
					</a>
					<a href="javascript:;" class="download"></a>
					<!-- <img id="file" src="img/img.png" /> -->
					<!-- <input type="file"> -->
				</div>
					
				<div class="foot-text">
					<textarea rows="6" cols="200" id="text">
					</textarea>
				</div>
				<div class="foot-send">
					<button type="button" id="button">发 送</button>
				</div>
			</div>
			
		</div>
		<script src="./socket.io/socket.io.js"></script>
		<script src="./js/index.js"></script>
		

		
	</body>
</html>

index.css

* {
	box-sizing: border-box;
	/* background-color: darkgrey; */
}

/* 聊天框整体 */
.box {
	display: block;
	border: 1px solid black;
	margin: 5rem 15rem;
	width: 60rem;
	height: 40rem;
	background-color: aliceblue;
}


.head{
	border: 1px solid skyblue;
	background-color: #87CEEB;
	height: 5%;
	text-align: center;
}

/* 对话框 */
.body{
	/* 悬浮emj表情  父元素*/
	position: relative;
	
	background-color: #F0F8FF;
	border: 1px solid blueviolet;
	height: 70%;
}
.body-left{
	background-color: white;
	border: 1px solid green;
	float: left;
	width: 20%;
	height: 100%;
}
.body-right{
	border: 1px solid yellow;
	float: right;
	width: 80%;
	height: 100%;
	overflow: scroll;
}
.card{
	height: 30%;
	border: 1px solid black;
}
.card1{
	height: 55%;
	border: 1px solid black;
	overflow: scroll;
}

/* 输入框 */
.foot{
	background-color: whitesmoke;
	border: 1px solid blueviolet;
	height: 25%;
}
.foot-tool{
	border: 1px solid black;
	height: 15%
	width: 100%;
	
}
.foot-text{
	border: 1px solid black;
	height: 50%;
	width: 100%;
	overflow: hidden;
}
.foot-send{
	border: 1px solid brown;
	height: 20%;
	width: 100%;
	overflow: hidden;
}


/* 清除默认格式 */
ul{
	
	 list-style-type: none;
	  margin: 0;
	  padding: 0.3125rem;
}

/* 设置按钮大小 */
button{
	background-color: dodgerblue;
	padding: 0.25rem 2.5rem;
	float: right;
}

/* 利用css给连接伪造一个图片 */
.foot .foot-tool .file {
  display: inline-block;
  vertical-align: middle;
  width: 40px;
  height: 45px;
  background: url('img/img.png') no-repeat ;
}
.foot .foot-tool .download {
  display: inline-block;
  vertical-align: middle;
  width: 40px;
  height: 45px;
  background: url('img/download.png') no-repeat ;
}
.foot .foot-tool .img {
  display: inline-block;
  vertical-align: middle;
  width: 40px;
  height: 45px;
  background: url('img/emj.png') no-repeat ;
}

.foot .foot-tool .file label {
  width: 100%;
  height: 100%;
  display: block;
}

/* 表情框 */
.emj{
	/* display: none; */
	display: grid;
	grid-gap: 1px;
	grid-template-columns: auto auto auto auto;
	position: fixed;
	top: 21.875rem;
	left: 16rem;	
	width: 12.5rem;
	height:12.5rem;
	border: 1px solid grey;
	background-color: gainsboro;
}
/* 规定网格大小 */
.emj > div{
	width: 3rem;
	height: 3rem;
	
}
/* 规定图片大小 */
div.emj img{
	width: 2.7rem;
	height: 2.7rem
}
/* 图片选择效果 */
div.emj img:hover{
	border: 1px solid grey;
	width: 3rem;
	height: 3rem
}

index.js

/* 
	聊天室的功能
	
	1.连接服务器 
	
	2.用户信息 
	//创建用户 (服务器创建用户,发送给该页面
	//销毁用户  (服务器销毁用户,发送给该页面
	
	
	3.用户发送消息 
	//个人用户向服务器发送
	//浏览器io给所有用户
	
	
*/
/* 1.连接服务器 */
var socket = io();

/* if(socket===null) */
//隐藏表情框
$("div.emj").hide();


//当前元素(最近一条消息)底部滚动到可视区
function scrollIntoView(n) {
	$(n).children(':last').get(0).scrollIntoView(false);
}
//查看历史消息

/* 2.用户信息 */
//创建全局变量
var name;
//接收服务器创建的用户
socket.on('send_name', function(data) {
	$("p.p1").empty();
	name = data;
	$("p.p1").append(`
	<p>请文明发言</p>
	<p class="p1">欢迎加入聊天,用户${data}</p>
	`);
});


//接收服务器销毁的用户,并且在.body-right输出
socket.on('remove_names', function(data) {
	$(".body-right").append(`<p style="text-align:center;color:grey">用户${data}偷偷离开了聊天室</p>`);
	scrollIntoView('.body-right');
});
//在.body-left输出所有用户的信息
socket.on('send_names', function(data) {
	//先清空
	$("ul").empty();
	/*测试: alert(data); */
	//统计聊天室成员
	data.forEach(item => {
		if (item > 0)
			$("ul").append("<li>用户" + item + "在线<li>");
	});
	scrollIntoView('.body-left');
});


/*              3.用户发送消息                  */

/*
 用户向服务器发送文字消息 
 */
$("#button").click(function() {
	var text = $("#text").val();
	/* 测试:alert(text); */
	//向服务器发送文字信息,type为txt
	socket.emit('send_app.js_text', {
		name: name,
		text: text,
		type: "txt"
	});
	//发送后内容清空
	$("#text").val("");
});
/* 
用户向服务器发送图片消息,type为img 
*/
$('#file').on('change', function() {
	var file = this.files[0]
	//需要把这个文件发送到服务器,借助于H5新增的fileReader
	var fr = new FileReader()
	fr.readAsDataURL(file)
	fr.onload = function() {
		/* 测试:alert(fr.result); */
		socket.emit('send_app.js_text', {
		 name: name,
			text: fr.result,
			type: "img"
		});
	}
});
/* 
用户向服务器发送表情包消息,type为emj
 */
//表情选取
	//鼠标移入表情包悬浮框显示
	$('a.img').on('mouseenter', function() {
		$(".emj").show();
	});
	//鼠标移出,表情包悬浮框消失
	$('div.emj').on('mouseleave', function() {
		$("div.emj").hide();
	});
//点击表情获取src属性
$("div.emj img").on('click',function(){
	/* 测试: alert($(this).attr("src")); */
	//加入聊天框
	socket.emit('send_app.js_text', {
	 name: name,
		text: $(this).attr("src"),
		type: "emj"
	});
	
});
	
/*                     4. 接收服务器发送的消息                       */
//用户消息
socket.on('send_message', function(data) {
	/* 测试 :alert(data); */
		$(".body-right").append(`
			<p style="text-align:center;color:grey">${data.time}</p>
			<p>用户${data.name}</p>
			`);
		if (data.type === "txt")
			$(".body-right").append(`<p>${data.text}</p>`);
		else if (data.type == "img")
			$(".body-right").append(`<img src="${data.text}" height=200px
	width=200px alt="" />`);
		else
			$(".body-right").append(`<img src="${data.text}" />`);
	scrollIntoView('.body-right');
});
//历史信息
socket.on('history_message', function(data) {
	$(".body-right").append(`
			<p style="text-align:center;color:grey">${data.time}</p>
			<p>用户${data.name}</p>
			`);
		//判断消息类型
		if (data.type === "txt")
			$(".body-right").append(`<p>${data.text}</p>`);
		else if (data.type == "img")
			$(".body-right").append(`<img src="${data.text}" height=200px
	width=200px alt="" />`);
		else
			$(".body-right").append(`<img src="${data.text}" />`);
});
历史信息数
socket.on('history_num', function(data) {
	$(".body-right").append(`<p style="text-align:center;color:grey">-------------------有${data}条历史消息记录------------</p>`);
	scrollIntoView('.body-right');
});

/* 下载消息 */

$('a.download').on('click',function(){
	socket.emit('download');
	alert("downlod");
/* 	socket.on('download', function(data) {
		var file = new ActiveXObject("Scripting.FileSystemObject");
		var fopen = file.CreateTextFile("../text.txt",true);
		data.forEach(item=>{
			alert("downlod");
			if(data.type === "txt")
			{
				alert("downlod");
				fopen.Write ("用户"+data.name+":");
				fopen.WriteLine (data.text);
			}
		});
		tf.Close();
	}); */
});

app.js

const { data } = require('jquery');
// 通过express创建了http服务器
var app = require('express')();
var http = require('http').Server(app);//httpServer要绑定的服务器
var io = require('socket.io')(http);
const db = require('./db/db.js');





//Express中static方法可以处理静态资源
//将public目录设置为静态资源目录
app.use(require('express').static('public'))
app.get('/', function(req, res){
  res.redirect('index.html')
});

/*获取当前时间*/
function getNowTime() {
    var date = new Date();
    //年 getFullYear():四位数字返回年份
    var year = date.getFullYear();  //getFullYear()代替getYear()
    //月 getMonth():0 ~ 11
    var month = date.getMonth() + 1;
    //日 getDate():(1 ~ 31)
    var day = date.getDate();
    //时 getHours():(0 ~ 23)
    var hour = date.getHours();
    //分 getMinutes(): (0 ~ 59)
    var minute = date.getMinutes();
    //秒 getSeconds():(0 ~ 59)
    var second = date.getSeconds();

    var time = ' ' + year + '-' + addZero(month) + '-' + addZero(day) + ' ' + addZero(hour) + ':' + addZero(minute) + ':' + addZero(second);
    return time;
}
function addZero(s) {
    return s < 10 ? ('0' + s) : s;
}



//加载历史消息
function initMessage(socket) {
    db.selectAll('select * from websocket order by id asc', (e, res) => {
        for (var i = 0; i < res.length; i++) {
			socket.emit('history_message', res[i]);
           /* 测试
		   console.log('历史消息:');
            console.log(res[i]); */
			
			//将历史消息加入messages中
			if(res[i].type === "img")
			{
						   messages.push({
						   			   name:res[i].name,
						   			   text:"图片消息",
						   }); 
			}			
			else
			{
				{
							   messages.push({
							   			   name:res[i].name,
							   			   text:res[i].text,
							   }); 
				}
			}
        }
		//发送历史消息数
		socket.emit('history_num',id);
		/* console.log('messages历史消息:');
		console.log(messages); */
		
    })
}

/* 定义全局变量 */

//用户名
var name = 0;
//总用户
var usernames = [];
//消息记录
var messages =[];



//用户连接事件
io.on('connection', function(socket){
	//加载数据库历史消息
 	db.selectAll('select count(*) as sum from websocket', (e, r) => {
	    console.log('数据库共有' + r[0].sum + '条历史消息记录')
		id = r[0].sum;
		//发送历史信息
		initMessage(socket);
	});
	
	/*                   2 .用户信息                         */
	//创建用户
	name = name+1;
	socket.name = name;
	//将该用户加入登录用户中
	usernames.push(name);
	// 向浏览器发送该用户
	socket.emit('send_name',name);
    // 向所有用户发送所有用户
    io.emit('send_names',usernames);
	
	/*                   3.给用户发送消息                 */
	// 接收浏览器信息
    socket.on('send_app.js_text',function(data){
           /* 测试 :console.log(message); */
		   
		    
		   let message = {
			   name:data.name,
			   time:getNowTime(),
			   text:data.text,
			   //通过type来区别信息
			   type:data.type
		   }
		   //计入数组
		   
		   //传入数据库
		   db.insertData('websocket', message, (e, r) => {
		       //测试
			   console.log('消息存入成功')
			   console.log(message); 
		   })
		   io.emit('send_message',message);
    });
	
	
	/*                              下载消息                           */
	 socket.on('download',function(){
		 console.log("开始下载"); 
		const fs = require("fs");
		messages.forEach(item=>{
			fs.appendFileSync("test.txt", "用户"+item.name+":\r\n"+item.text+"\r\n\r\n");
			let data = fs.readFileSync("test.txt", "utf8");
			console.log(data); // Hello world
			})
		});
		
		
	
	
	/*                 监听某位用户断开连接事件(自带功能,不需要浏览器emit)                */
	socket.on('disconnect',function(data){
		//找到该用户并移出数组(删除用户)	
		for(i=0;i<usernames.length;i++){
			if(usernames[i] == socket.name)
			usernames[i]=-1;
		}
		/*	测试
		usernames.forEach(item=>{
			console.log(item);
		}); 	*/
		//向所有用户发送离开信息
		io.emit('send_names',usernames);
		//在列表移除用户
		io.emit('remove_names',socket.name);
		
	});
		
	
});



/*  */

//指定端口号为3000
http.listen(3000, function(){
  console.log('listening on *:3000');
});

db.js

const conn = require('./config');
const connection = conn();
// 查询所有数据
let selectAll = (sql,callback)=>{
  connection.query(sql,(err,result)=>{
    if(err){
        console.log('错误信息-',err.sqlMessage);
        let errNews = err.sqlMessage;
        callback(errNews,'');
        return;
    } 
    var string=JSON.stringify(result); 
    var data = JSON.parse(string);
    callback('',data);
    // console.log(string);
  })
}
// 插入一条数据
let insertData = (table,datas,callback)=>{
  var fields='';
  var values='';
  for( var k in datas){
      fields+=k+',';
      values=values+"'"+datas[k]+"',"
  }
  fields=fields.slice(0,-1);
  values=values.slice(0,-1);
  console.log(fields,values);
  var sql="INSERT INTO "+table+'('+fields+') VALUES('+values+')';
  connection.query(sql,callback);
}



// 删除一条数据
let deleteData=function(table,where,callback){
    var _WHERE='';
    for(var k2 in where){
      //多个筛选条件使用  _WHERE+=k2+"='"+where[k2]+"' AND ";
      _WHERE+= k2+"="+where[k2];
    }
    // DELETE  FROM user WHERE UserId=12  注意UserId的数据类型要和数据库一致
    var sql="DELETE  FROM "+table+' WHERE '+_WHERE;
    connection.query(sql,callback);
}


exports.selectAll = selectAll;
exports.insertData = insertData;
exports.deleteData = deleteData;

config.js

const mysql = require('mysql')

const connectdb=()=>{
  var connection = mysql.createConnection({     
    host     : 'localhost',       
    user     : 'root',              
    password : '123456',       
    port: '3306',                   
    database: 'websocket' 
})
  return connection;
}

module.exports=connectdb;

至此,此次课设的全部任务以及完成了,下面是拓展功能



最终界面

本来想使用,但是没找到具体用法,自己想了一个其他办法
利用点击事件选取要发送的用户并且获取id,传值,在服务器中判断是否id有值,如果有则是私聊,没有就是公聊。再在浏览器判断当前用户是否为传值中的两个用户,如果是则显示私聊界面。

html

<!DOCTYPE html>
<html >
	<head>
		<meta charset="UTF-8">
		<title>聊天室</title>
		<link rel="stylesheet" type="text/css" href="index.css"> 
		<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
	</head>
	<body>
		<div class="box">
			
			<div class="head">
				聊天室
				<button class="but2">X</button>
			</div>

			<div class="body">
				<!-- 用户信息栏 -->
				
				<div class="body-left">
					<div class="card">
						<h3>公告栏</h3>
						<p class="p1">欢迎加入聊天,用户</p>
					</div>
					<h3>聊天室成员</h3>
					<div class="card1">
							<!-- 
							$(".card1").append(`<a href="javascript:;" class="li">用户  ${item}  在线</a>`);
							 -->
					</div>		
				</div>
				<!-- 聊天信息框 -->
				<div class="body-right1">
					<p style="text-align:center;color:grey">----------此界面为临时聊天框,离开消息即清空---------</p>
				</div>
				<div class="body-right">
				
				</div>
			</div>
			<!-- 表情框,初始为隐藏 -->
			<div class="emj">
				<div> <img src="emj/1.png" /> </div>
				<div> <img src="emj/2.png" /> </div>
				<div> <img src="emj/3.png" /> </div>
				<div> <img src="emj/4.png" /> </div>
				<div> <img src="emj/5.png" /> </div>
				<div> <img src="emj/6.png" /> </div>
				<div> <img src="emj/7.png" /> </div>
				<div> <img src="emj/8.png" /> </div>
				<div> <img src="emj/9.png" /> </div>
				<div> <img src="emj/10.png" /> </div>
				<div> <img src="emj/11.png" /> </div>
				<div> <img src="emj/12.png" /> </div>
				<div> <img src="emj/13.png" /> </div>
				<div> <img src="emj/14.png" /> </div>
				<div> <img src="emj/15.png" /> </div>
				<div> <img src="emj/16.png" /> </div>
			</div>
			<div class="foot">
				<div class="foot-tool">
					<a href="javascript:;" class="img"></a>
					<a href="javascript:;"  class="file">
					  <label for="file"></label>
					  <input type="file" id="file" style="display: none;">
					</a>
					<a href="javascript:;" class="download"></a>
					<!-- <img id="file" src="img/img.png" /> -->
					<!-- <input type="file"> -->
				</div>
					
				<div class="foot-text">
					<textarea rows="6" cols="200" id="text">
					</textarea>
				</div>
				<div class="foot-send">
					<button type="button" class="but1">发 送</button>
				</div>
			</div>
			
		</div>
		<script src="./socket.io/socket.io.js"></script>
		<script src="./js/index.js"></script>
		

		
	</body>
</html>

css

::-webkit-scrollbar {
/*隐藏滚轮*/
display: none;
}

* {
	box-sizing: border-box;
	/* background-color: darkgrey; */
}

body{
	background-color: darkseagreen;
}
/* 聊天框整体 */
.box {
	display: block;
	border: 1px solid black;
	margin: 5rem 15rem;
	width: 60rem;
	height: 40rem;
	background-color: aliceblue;
}


.head{
	border: 1px solid skyblue;
	background-color: #87CEEB;
	height: 7%;
	text-align: center;
}

/* 对话框 */
.body{
	/* 悬浮emj表情  父元素*/
	position: relative;
	
	background-color: #F0F8FF;
	/* border: 1px solid blueviolet; */
	height: 70%;
}
.body-left{
	background-color: white;
	/* border: 1px solid green; */
	float: left;
	width: 20%;
	height: 100%;
}
.body-right1{
	position: fixed;
	border: 1px solid black;
	float: right;
	width: 59.95rem;
	height: 27.9rem;
	overflow: scroll;
	background: url('picture/background.jpg' ) no-repeat;
	background-size: 100%;
	opacity:0.8;
}
.body-right{
	border: 1px solid black;
	float: right;
	width: 80%;
	height: 100%;
	overflow: scroll;
}
.card{
	height: 30%;
	border: 1px solid black;
}
.card1{
	height: 56%;
	border: 1px solid black;
	overflow: scroll;
}

/* 输入框 */
.foot{
	background-color: whitesmoke;
	/* border: 1px solid blueviolet; */
	height: 22%;
}
.foot-tool{
	background-color: #DCDCDC;
	border: 1px solid black;
	height: 15%
	width: 100%;
	
}
.foot-text{
	/* border: 1px solid black; */
	background-color: white;
	height: 50%;
	width: 100%;
	overflow: hidden;
}
.foot-send{
	/* border: 1px solid brown; */
	background-color: white;
	height: 20%;
	width: 100%;
	overflow: hidden;
}

/* 设置按钮大小 */
.but1{
	background-color: dodgerblue;
	padding: 0.25rem 2.5rem;
	float: right;
}
.but2{
	background-color: red;
	float: right;
}


/* 利用css给连接伪造一个图片 */
.foot .foot-tool .file {
  display: inline-block;
  vertical-align: middle;
  width: 40px;
  height: 45px;
  background: url('picture/img.png') no-repeat ;
}
.foot .foot-tool .download {
  display: inline-block;
  vertical-align: middle;
  width: 40px;
  height: 45px;
  background: url('picture/download.png') no-repeat ;
}
.foot .foot-tool .img {
  display: inline-block;
  vertical-align: middle;
  width: 40px;
  height: 45px;
  background: url('picture/emj.png') no-repeat ;
}

.foot .foot-tool .file label {
  width: 100%;
  height: 100%;
  display: block;
}

/* 表情框 */
.emj{
	/* display: none; */
	display: grid;
	grid-gap: 1px;
	grid-template-columns: auto auto auto auto;
	position: fixed;
	top: 21.875rem;
	left: 16rem;	
	width: 12.5rem;
	height:12.5rem;
	border: 1px solid grey;
	background-color: gainsboro;
}
/* 规定网格大小 */
.emj > div{
	width: 3rem;
	height: 3rem;
	background-color:#F0F8FF;
	
}
/* 规定图片大小 */
div.emj img{
	width: 2.7rem;
	height: 2.7rem
}
/* 图片选择效果 */
div.emj img:hover{
	border: 1px solid grey;
	width: 3rem;
	height: 3rem
}

/* 当鼠标移点击页面时自动对焦到第一行 */


/* 清除默认样式 */
.body .body-left a {
	display: block;
	text-decoration:none;
	padding: 0.3125rem;
	color: #000000;
}
.right{
	/*消息排版会乱掉 
	1.float: right;
	2.position:absolute;
	    right:50px; 
		*/
	float: right;
	 clear:both;
}
.left{
	/* float: left; */
	 clear:both;
}

index.js

/* 
	聊天室的功能
	
	1.连接服务器 
	
	2.用户信息 
	//创建用户 (服务器创建用户,发送给该页面
	//销毁用户  (服务器销毁用户,发送给该页面
	
	
	3.用户发送消息 
	//个人用户向服务器发送
	//浏览器io给所有用户
	
	
*/
/* 1.连接服务器 */
var socket = io();

/* if(socket===null) */
//隐藏表情框
$("div.emj").hide();
//隐藏返回按钮
$(".but2").hide();
//隐藏对话框
$(".body-right1").hide();

//当前元素(最近一条消息)底部滚动到可视区
function scrollIntoView(n) {
	$(n).children(':last').get(0).scrollIntoView(false);
}
//查看历史消息
socket.emit('history');

/* 2.用户信息 */
//创建全局变量
var name;
//被选中的用户(只有点击后才不为0)
var p_id=0;
//接收服务器创建的用户
socket.on('send_name', function(data) {
	$("p.p1").empty();
	name = data;
	$("p.p1").append(`
	<p>请文明发言</p>
	<p class="p1">欢迎加入聊天,用户${data}</p>
	`);
});


//接收服务器销毁的用户,并且在.body-right输出
socket.on('remove_names', function(data) {
	$(".body-right").append(`<p style="text-align:center;color:grey">用户${data}偷偷离开了聊天室</p>`);
	scrollIntoView('.body-right');
});
//在.body-left输出所有用户的信息
socket.on('send_names', function(data) {
	//先清空
	$(".card1").empty();
	/*测试: alert(data); */
	//统计聊天室成员
	data.forEach(item => {
		if (item > 0)
			$(".card1").append(`<a href="javascript:;" class="li" id="${item}">用户  ${item}  在线</a>`);
	});
	scrollIntoView('.body-left');
});


/*              3.用户发送消息                  */

/*
 用户向服务器发送文字消息 
 */
//
//点击发送
$("button.but1").click(function() {
	var text = $("#text").val();
	/* 测试:alert(text); */
	//向服务器发送文字信息,type为txt
	socket.emit('send_app.js_text', {
		name: name,
		text: text,
		type: "txt"
	},p_id);
	//发送后内容清空
	$("#text").val("");
});
/* 
用户向服务器发送图片消息,type为img 
*/
$('#file').on('change', function() {
	var file = this.files[0]
	//需要把这个文件发送到服务器,借助于H5新增的fileReader
	var fr = new FileReader()
	fr.readAsDataURL(file);
	fr.onload = function() {
		/* 测试:alert(fr.result); */
		socket.emit('send_app.js_text', {
		 name: name,
			text: fr.result,
			type: "img"
		},p_id);
	}
});
/* 
用户向服务器发送表情包消息,type为emj
 */
//表情选取
	//鼠标移入表情包悬浮框显示
	$('a.img').on('mouseenter', function() {
		$(".emj").show();
	});
	//鼠标移出,表情包悬浮框消失
	$('div.emj').on('mouseleave', function() {
		$("div.emj").hide();
	});
//点击表情获取src属性
$("div.emj img").on('click',function(){
	/* 测试: alert($(this).attr("src")); */
	//加入聊天框
	socket.emit('send_app.js_text', {
	 name: name,
		text: $(this).attr("src"),
		type: "emj"
	},p_id);
	
});
	
/*                     4. 接收服务器发送的消息                       */
//用户消息
socket.on('send_message', function(data) {
	/* 测试 :alert(data); */
		$(".body-right").append(`
			<p style="text-align:center;color:grey">${data.time}</p>
			<p>用户${data.name}</p>
			`);
		if (data.type === "txt")
			$(".body-right").append(`<p>${data.text}</p>`);
		else if (data.type == "img")
			$(".body-right").append(`<img src="${data.text}" height=200px
	width=200px alt="" />`);
		else
			$(".body-right").append(`<img src="${data.text}" />`);
	scrollIntoView('.body-right');
});
//历史信息

//历史信息数
socket.on('history_num', function(data) {
	$(".body-right").append(`<p style="text-align:center;color:grey">-------------------有${data}条历史消息记录------------</p>`);
	scrollIntoView('.body-right');
});

/* 下载消息 */
$('a.download').on('click',function(){
	socket.emit('download');
	alert("下载成功");
});

/*                          私聊功能                       */
//双击左边聊天室成员,和其私聊( .body-right1悬浮窗显示,显示返回按钮
$('.card1').on('click','a.li',function(){
	/* alert($(this).attr('id')); */
	p_id=$(this).attr('id');
	if(p_id===name){
		alert("不能与自己聊天")
		//flag判断是否与自己聊天
		var flag=-1;
	}
	if(flag!=-1){
		$(".body-right1").empty();
		$(".body-left").hide();
		$(".body-right").hide();
		$(".but2").show();
		$(".body-right1").show();
	}
	flag=0;
});
//只能这两个用户可以看到消息
socket.on('private_message', function(data) {
	/* $(".body-right1").empty(); */
	if(data.send_name===name||data.save_name===name){
		$(".body-left").hide();
		$(".body-right").hide();
		$(".but2").show();
		$(".body-right1").show();
		//如果是自己发信息,在右边;别人的在左边
		if(data.send_name===name)
		{
			//!!!!!!!!!!!!!!!!!!!!更换p_id
			p_id=data.save_name;
			direction="left"
		}
		else
			direction="right";
		$(".body-right1").append(`
				<p style="text-align:center;color:grey">${data.time}</p>`);
		if (data.type === "txt")
				$(".body-right1").append(`
				<div class="${direction}">
				<p style="text-align:${direction} ">用户${data.save_name}</p>
				<p>${data.text}</p>
				</div>`);
		else if (data.type == "img")
				$(".body-right1").append(`
				<div class="{direction}">
					<p style="text-align:${direction} ">用户${data.save_name}</p>
					<img src="${data.text}" height=200px width=200px alt="" />
				</div>`);
		else
				$(".body-right1").append(`
				<div class="{direction}">
					<p style="text-align:${direction} ">用户${data.save_name}</p>
					<img src="${data.text}" />
				</div>`);
		scrollIntoView('.body-right1');
		
		//
		
	}
});


//返回界面
$('.head').on('click','button.but2',function(){
	$(".body-right").empty();
	$(".body-right1").empty();
	$(".but2").hide();
	$(".body-right1").hide();
	$(".body-left").show();
	$(".body-right").show();
	//判断条件恢复
	p_id=0;
	//调用历史消息
	socket.emit('history');
	//
	socket.emit('leave');
});

socket.on('leaves', function() {
			$(".body-right1").append(`<p style="text-align:center;color:grey">另一位用户已离开私聊界面</p>`);
			scrollIntoView('.body-right1');
		});

app.js

const { data } = require('jquery');
// 通过express创建了http服务器
var app = require('express')();
var http = require('http').Server(app);//httpServer要绑定的服务器
var io = require('socket.io')(http);
const db = require('./db/db.js');





//Express中static方法可以处理静态资源
//将public目录设置为静态资源目录
app.use(require('express').static('public'))
app.get('/', function(req, res){
  res.redirect('index.html')
});

/*获取当前时间*/
function getNowTime() {
    var date = new Date();
    //年 getFullYear():四位数字返回年份
    var year = date.getFullYear();  //getFullYear()代替getYear()
    //月 getMonth():0 ~ 11
    var month = date.getMonth() + 1;
    //日 getDate():(1 ~ 31)
    var day = date.getDate();
    //时 getHours():(0 ~ 23)
    var hour = date.getHours();
    //分 getMinutes(): (0 ~ 59)
    var minute = date.getMinutes();
    //秒 getSeconds():(0 ~ 59)
    var second = date.getSeconds();

    var time = ' ' + year + '-' + addZero(month) + '-' + addZero(day) + ' ' + addZero(hour) + ':' + addZero(minute) + ':' + addZero(second);
    return time;
}
function addZero(s) {
    return s < 10 ? ('0' + s) : s;
}



//加载历史消息
function initMessage(socket) {
    db.selectAll('select * from websocket order by id asc', (e, res) => {
        for (var i = 0; i < res.length; i++) {
			socket.emit('send_message', res[i]);
           /* 测试
		   console.log('历史消息:');
            console.log(res[i]); */
			
			//将历史消息加入messages中
			if(res[i].type === "img")
			{
						   messages.push({
						   			   name:res[i].name,
						   			   text:"图片消息",
						   }); 
			}			
			else
			{
							 messages.push({
						   			   name:res[i].name,
						   			   text:res[i].text,
						   }); 
			}	
        }
		//发送历史消息数
		socket.emit('history_num',id);
		/* console.log('messages历史消息:');
		console.log(messages); */
		
    })
}

/* 定义全局变量 */

//用户名
var name = 0;
//总用户
var usernames = [];
//消息记录
var messages =[];
var private_message=[];



//用户连接事件
io.on('connection', function(socket){
	//加载数据库历史消息
	socket.on('history',function(){
		db.selectAll('select count(*) as sum from websocket', (e, r) => {
		    console.log('数据库共有' + r[0].sum + '条历史消息记录')
			id = r[0].sum;
			//发送历史信息
			initMessage(socket);
		});
	})
 	
	
	/*                   2 .用户信息                         */
	//创建用户
	name = name+1;
	socket.name = name;
	//将该用户加入登录用户中
	usernames.push(name);
	// 向浏览器发送该用户
	socket.emit('send_name',name);
    // 向所有用户发送所有用户
    io.emit('send_names',usernames);
	
	/*                   3.给用户发送消息                 */
	// 接收浏览器信息
    socket.on('send_app.js_text',function(data,id){
		/* console.log(id); */
		//聊天室
		
		if (id===0)
			{
				let message = {
					name: data.name,
					time: getNowTime(),
					text: data.text,
					//通过type来区别信息
					type: data.type
				}
				//当前消息存入数组
				if (data.type === "img") {
					messages.push({
						name: data.name,
						text: "图片消息",
					});
				} else {
					messages.push({
						name: data.name,
						text: data.text,
					});
				}
				//传入数据库
				db.insertData('websocket', message, (e, r) => {
					//测试
					console.log('消息存入成功')
					console.log(message);
				})
		
				io.emit('send_message', message);
			}
			//私聊,通过send_name和save_name实现
			//数据使用数组保存,可以不存入数据库
			else
			{
				console.log(id)
				private_message = {
					send_name:id,
					save_name:data.name,
					time: getNowTime(),
					text: data.text,
					//通过type来区别信息
					type: data.type
				}
/* 				console.log(private_message.send_name);
				console.log(private_message.save_name); */
				io.emit('private_message', private_message);
			}
		
		});
	
	
	/*                              下载消息                           */
	 socket.on('download',function(){
		 console.log("开始下载"); 
		const fs = require("fs");
		messages.forEach(item=>{
			fs.appendFileSync("test.txt", "用户"+item.name+":   "+item.text+"\r\n\r\n");
			let data = fs.readFileSync("test.txt", "utf8");
			console.log(data); 
			})
		});
		
	/*                 监听某位用户断开连接事件(自带功能,不需要浏览器emit)                */
	socket.on('disconnect',function(data){
		//找到该用户并移出数组(删除用户)	
		for(i=0;i<usernames.length;i++){
			if(usernames[i] == socket.name)
			usernames[i]=-1;
		}
		/*	测试
		usernames.forEach(item=>{
			console.log(item);
		}); 	*/
		//向所有用户发送离开信息
		io.emit('send_names',usernames);
		//在列表移除用户
		io.emit('remove_names',socket.name);
		//私聊界面
		socket.on('leave',function(){
			io.emit('leaves');
		});	
		
	});
	
	
	/*                             私聊                     */
	
	/* if (id===0)
		公共
	else
		私聊
	*/
	//	一个用户退出,告知另一个
	socket.on('leave',function(){
		io.emit('leaves');
	});	
	
});



/*  */

//指定端口号为3000
http.listen(3000, function(){
  console.log('listening on *:3000');
});
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值