微信聊天
app.js
var express = require('express');
var app = express();//实例化一个express的app服务器 创建express服务器 不是必要的
var fs = require('fs');
var http = require('http');
var http1 = http.Server(app);//把app的这个服务器传到 原生的http服务器中
var io = require('socket.io');//引用socket.io模块
var socket = io(http1);//socket的实例化 创建了 以http1 为服务器的 socket的 协议服务器
var path=require('path')
app.use(express.static(path.join(__dirname,'static')));
app.get('/',function (req,res) {
fs.readFile('./index.html',function (err,data) {
if(err){
throw err;
}
res.end(data);
})
})
socket.on('connection',function (socket) {
socket.on('myMessage',function (data) {//当客服端有用户发送信息的时候
socket.broadcast.emit('oterFriend',data);//广播信息给其他客服端
})
socket.on('newFriend',function (data) {
socket.broadcast.emit('message',data);
})
})
http1.listen(8081);
index.html
<style type="text/css">
::-webkit-scrollbar {
width: 0px;
}
*{
margin: 0;
padding: 0;
}
/*聊天界面的大盒子*/
.box{
width: 360px;
height: 500px;
margin: 30px auto;
}
#max {
list-style: none;
width: 340px;
height: 400px;
margin: 0 auto;
overflow-y: auto;
background-color: #fbfbfb;
}
/*每一条聊天信息
给其他客服端的信息加上左浮动*/
#max li{
position: relative;
float: left;
margin-left: 11px;
margin-top: 23px;
padding: 5px 10px;
max-width: 200px;
height: auto;
background: #fff;
color: #333;
clear: both;
word-break: break-all;
}
/*给自己发送的信息加上右浮动*/
li.f_r{
float:right !important;
clear: both !important;
background: #a3d54e !important;
color: #333 !important;
margin-right: 11px;
}
/*新好友上线提示框*/
#p_f{
position: fixed;
left: 4px;
top: 4px;
width: 150px;
height: 32px;
line-height: 32px;
background-color: aquamarine;
box-shadow:0 0 6px rgba(0,0,0,.4);
}
/*发送信息功能区盒子*/
.message{
width: 340px;
margin: 0 auto;
background-color: #e5e5e5;
border-top: 1px solid #d2cfcf;
height: 40px;
line-height: 40px;
}
/*图标按钮*/
#ejmo{
float: left;
width: 26px;
height: 26px;
background: url('images/ejom.png');
background-size: 100%;
cursor: pointer;
margin-left: 10px;
margin-top: 7px;
position: relative;
}
.biaoqian{
width: 360px;
margin-top: 40px;
}
/*全部表情图片*/
.biaoqian img{
display: inline-block;
width: 26px;
height: 26px;
margin-right: 18px;
margin-top: 8px;
}
/*表情的切换页圆点*/
#subNum{
text-align: center;
display: none;
}
#subNum li{
margin-left: 10px;
display: inline-block;
list-style: none;
width: 10px;
height: 10px;
border-radius: 50%;
background: #BBBBBB;
cursor: pointer;
}
/*发送文本框和发送按钮*/
#userval,#btn{
float: right;
margin-right: 10px;
margin-top: 3px;
border: none;
border-radius: 4px;
}
#userval{
width: 210px;
height: 24px;
padding: 4px;
background: white;
line-height: 24px;
overflow:hidden;
}
/*发送按钮*/
#btn{
width: 50px;
height: 30px;
background: #05c25e;
color: white;
}
.triangleLeft,.triangleRight{
position: absolute;
width: 0;
height: 0;
border-width: 6px;
border-style: solid;
top: 7px;
}
/*每条信息旁边的右三角形*/
.triangleRight{
border-color:transparent transparent transparent #a3d54e;
right: -11px;
}
/*每条信息旁边的左三角形*/
.triangleLeft{
border-color:transparent white transparent transparent;
left: -11px;
}
.timer{
position: absolute;
width: 320px;
text-align: center;
top: -17px;
right: 0;
}
</style>
</head>
<body >
<div class="box">
<!--信息记录-->
<ul id="max">
</ul>
<!--发信息功能区-->
<div class="message">
<!--表情-->
<div id="ejmo"></div>
<!--文本输入框-->
<input type="button" id="btn" value="发送" />
<p id="userval" contenteditable="true"></p>
<!--表情大全-->
<dl class="biaoqian"></dl>
<!--切换表情页-->
<ul id="subNum">
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
</div>
</body>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.dev.js"></script>
<script type="text/javascript">
//封装获取id的方法
function $(ele){
return document.getElementById(ele);
}
//前端没有传入任何的服务器 默认会传入当前服务器
var socket = io();
//当用户第一次进入页面的时候 给其他客服端发送提示
//刷新页面的时候 如果我们已经登录过的状态的时候 不应该提醒另外的客户端 新用户上线
socket.emit('newFriend','有新的好友进入聊天室..');
//监听当有新用户加入的时候
socket.on('message',function(data){
var p=document.createElement('p');
p.innerHTML=data;
p.id='p_f';
document.body.appendChild(p);
//获取上面创建新用户进入提示的p元素
var alertBox=$('p_f');
var num=0;
var timer=setInterval(function(){
num++;
if(num>5){
//显示5秒后 删除新用户进入提示的p元素
alertBox.remove();
clearInterval('timer');
}
},1000)
});
//当收到其他客服端发送的消息的时候 在页面上显示其他客服端发送的消息
socket.on('oterFriend',function (obj) {
craeteLi(obj,'','<span class="triangleLeft"></span>')
});
//当点击发送信息按钮的时候
var btn=$('btn');//发送消息按钮
var val=$('userval');//消息输入框
btn.onclick = function () {
if(val.innerHTML!=''){
//给发送给服务器显示给它客服端显示当前发送的信息
socket.emit('myMessage',val.innerHTML);
craeteLi(val.innerHTML,'f_r','<span class="triangleRight"></span>');
val.innerHTML='';//点击发送后清空当前文本框
}
}
//发送一条消息或者 接受一条消息就往ul消息大盒子中 创建li节点
function craeteLi(val,cla,fx){
var oLi=document.createElement('li');
//获取时间盒子
var oSpan=document.getElementsByClassName('timer');
//获取当前的时间
var newDate=`${new Date().getHours()}:${new Date().getMinutes()}`;
var timer=`<span class="timer">${newDate}</sapn>`.toString();
for(var i=0;i<oSpan.length;i++){
if(oSpan[i].innerHTML==newDate){
timer='';
}
}
oLi.innerHTML=val+fx+timer;
oLi.className=cla;
$('max').appendChild(oLi);//包裹聊天信息的ul大盒子
$('max').scrollTop=$('max').scrollHeight;
};
//装表情图的大盒子
var biaoQ=document.getElementsByClassName('biaoqian')[0];
var toggle=true;
//点击表情图标 显示装表情图的大盒子
$('ejmo').onclick=function(){
if(toggle==true){
toggle=false;
biaoQ.style.display='block';
//切换表情页的小圆点
$('subNum').style.display='block';
//首次点击表情图标后显示第一页的24个表情
toggleImg(0,24)
}else{
toggle=true
biaoQ.style.display='none';
$('subNum').style.display='none';
}
}
//切换表情图标的小圆点页
var biaoPage=$('subNum').getElementsByTagName('li');
for(var i=0;i<biaoPage.length;i++){
biaoPage[i].index=i+1;
biaoPage[i].onclick=function(){//点击小圆点切换相应的图片
//自定义属性*24-24为当前表情图片序号最小值 自定义属性*24为当前表情图片序号最大值 一页表情24个表情图标
toggleImg(this.index*24-24,this.index*24);
}
}
//点击图标页的小圆点 切换相应的表情页封装函数
function toggleImg(min,max){
var str='';
for(var i=min;i<max;i++){
var str1='<img src="images\\arclist\\'+i+'.gif">';
str+=`<img src="images/arclist/${i}.gif">`;
}
biaoQ.innerHTML=str;
$('subNum').style.display='block';
}
//阻止contenteditable 输入框回车换行的默认事件
val.onkeydown=function(e){
if(e.keyCode==13){
btn.click();
e.preventDefault();
}
}
//点击某个表情图标的时候 插入点击的表情图标到内容输入框
biaoQ.onclick=function(ev){
if(ev.target.nodeName=='IMG'){
var imgSrc=ev.srcElement.currentSrc.split('arclist/')[1];
val.focus();
insertHtmlAtCaret(`<img src="images/arclist/${imgSrc}">`);//插入表情到输入框
}
}
//解决在输入框不能在光标位置插入表情的函数封装
function insertHtmlAtCaret(html) {
var sel, range;
if (window.getSelection) {
// IE9 and non-IE
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
// Range.createContextualFragment() would be useful here but is
// non-standard and not supported in all browsers (IE9, for one)
var el = document.createElement("div");
el.innerHTML = html;
var frag = document.createDocumentFragment(), node, lastNode;
while ((node = el.firstChild)) {
lastNode = frag.appendChild(node);
}
range.insertNode(frag);
// Preserve the selection
if (lastNode) {
range = range.cloneRange();
range.setStartAfter(lastNode);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
}
}else if (document.selection && document.selection.type != "Control") {
document.selection.createRange().pasteHTML(html);
}
}
</script>