微信聊天
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>