H5+MUI+Node.js+Socket.io实现即时聊天以及发送+图片压缩
Posted 云上人间钦自赏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了H5+MUI+Node.js+Socket.io实现即时聊天以及发送+图片压缩相关的知识,希望对你有一定的参考价值。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <title></title> <link href="css/mui.min.css" rel="stylesheet" /> <!--<link rel="stylesheet" type="text/css" href="css/app.css" />--> <link href="css/mui.imageviewer.css" rel="stylesheet" />//发送图片后,点击图片大图预览用的 <link rel="stylesheet" href="css/iconfont.css"> <!–[if lt IE 8]><script src="js/json3.js"></script><![endif]–> <style type="text/css"> .mui-bar-nav { background-color: #00abed; -webkit-box-shadow: none; box-shadow: none; } .mui-bar { height: 80px; line-height: 80px; } .mui-title { color: #fff; font-weight: bold; } .msg-my-img{ float: right; width: 38px; height: 38px; border-radius: 3px; color: #ddd; vertical-align: top; text-align: center; } </style> <style> html, body { height: 100%; margin: 0px; padding: 0px; overflow: hidden; -webkit-touch-callout: none; -webkit-user-select: none; } footer { position: fixed; width: 100%; height: 50px; min-height: 50px; border-top: solid 1px #bbb; left: 0px; bottom: 0px; overflow: hidden; padding: 0px 50px; background-color: #fafafa; } .footer-left { position: absolute; width: 50px; height: 50px; left: 0px; bottom: 0px; text-align: center; vertical-align: middle; line-height: 100%; padding: 12px 4px; } .footer-right { position: absolute; width: 50px; height: 50px; right: 0px; bottom: 0px; text-align: center; vertical-align: middle; line-height: 100%; padding: 12px 5px; padding-top:15px; display: inline-block; } .footer-center { height: 100%; padding: 5px 0px; position: absolute; left:50px; right: 50px; } .footer-center [class*=input] { width: 100%; height: 100%; border-radius: 5px; } .footer-center .input-text { background: #fff; border: solid 1px #ddd; padding: 10px !important; font-size: 16px !important; line-height: 18px !important; font-family: verdana !important; overflow: hidden; } .footer-center .input-sound { background-color: #eee; } .mui-content { height: 100%; padding: 44px 0px 50px 0px; overflow: auto; background-color: #eaeaea; } #msg-list { height: 100%; overflow: auto; -webkit-overflow-scrolling: touch; } .msg-item { padding: 8px; clear: both; } .msg-item .mui-item-clear { clear: both; } .msg-item .msg-user { width: 38px; height: 38px; border: solid 1px #d3d3d3; display: inline-block; background: #fff; border-radius: 3px; vertical-align: top; text-align: center; float: left; padding: 3px; color: #ddd; } .msg-item .msg-user-img{ width: 38px; height: 38px; display: inline-block; border-radius: 3px; vertical-align: top; text-align: center; float: left; color: #ddd; } .msg-item .msg-content { display: inline-block; border-radius: 5px; border: solid 1px #d3d3d3; background-color: #FFFFFF; color: #333; padding: 8px; vertical-align: top; font-size: 15px; position: relative; margin: 0px 8px; max-width: 75%; min-width: 35px; float: left; word-break:break-all; } .msg-item .msg-content .msg-content-inner { overflow-x: hidden; } .msg-item .msg-content .msg-content-arrow { position: absolute; border: solid 1px #d3d3d3; border-right: none; border-top: none; background-color: #FFFFFF; width: 10px; height: 10px; left: -5px; top: 12px; -webkit-transform: rotateZ(45deg); transform: rotateZ(45deg); } .msg-item-self .msg-user, .msg-item-self .msg-content { float: right; } .msg-item-self .msg-content .msg-content-arrow { left: auto; right: -5px; -webkit-transform: rotateZ(225deg); transform: rotateZ(225deg); } .msg-item-self .msg-content, .msg-item-self .msg-content .msg-content-arrow { background-color: #4CD964; color: #fff; border-color: #2AC845; word-break:break-all; } footer .mui-icon { color: #000; } footer .mui-icon:active { color: #007AFF !important; } footer .mui-icon-paperplane:before { content: "发送"; } footer .mui-icon-paperplane { /*-webkit-transform: rotateZ(45deg); transform: rotateZ(45deg);*/ font-size: 16px; word-break: keep-all; line-height: 100%; padding-top: 6px; color: rgba(0, 135, 250, 1); font-style: normal; } #msg-sound { -webkit-user-select: none !important; user-select: none !important; } .rprogress { position: absolute; left: 50%; top: 50%; width: 140px; height: 140px; margin-left: -70px; margin-top: -70px; background-image: url(../images/arecord.png); background-repeat: no-repeat; background-position: center center; background-size: 30px 30px; background-color: rgba(0, 0, 0, 0.7); border-radius: 5px; display: none; -webkit-transition: .15s; } .rschedule { background-color: rgba(0, 0, 0, 0); border: 5px solid rgba(0, 183, 229, 0.9); opacity: .9; border-left: 5px solid rgba(0, 0, 0, 0); border-right: 5px solid rgba(0, 0, 0, 0); border-radius: 50px; box-shadow: 0 0 15px #2187e7; width: 46px; height: 46px; position: absolute; left: 50%; top: 50%; margin-left: -23px; margin-top: -23px; -webkit-animation: spin 1s infinite linear; animation: spin 1s infinite linear; } .r-sigh{ display: none; border-radius: 50px; box-shadow: 0 0 15px #2187e7; width: 46px; height: 46px; position: absolute; left: 50%; top: 50%; margin-left: -23px; margin-top: -23px; text-align: center; line-height: 46px; font-size: 40px; font-weight: bold; color: #2187e7; } .rprogress-sigh{ background-image: none !important; } .rprogress-sigh .rschedule{ display: none !important; } .rprogress-sigh .r-sigh{ display: block !important; } .rsalert { font-size: 12px; color: #bbb; text-align: center; position: absolute; border-radius: 5px; width: 130px; margin: 5px 5px; padding: 5px; left: 0px; bottom: 0px; } @-webkit-keyframes spin { 0% { -webkit-transform: rotate(0deg); } 100% { -webkit-transform: rotate(360deg); } } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } #h { background: #fff; border: solid 1px #ddd; padding: 10px !important; font-size: 16px !important; font-family: verdana !important; line-height: 18px !important; overflow: visible; position: absolute; left: -1000px; right: 0px; word-break: break-all; word-wrap: break-word; } .cancel { background-color: darkred; } </style> </head> <body contextmenu="return false;"> <header class="mui-bar mui-bar-nav"> <div style="margin-top:30px;"> <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left" style="color: #fff;font-size: 26px;"></a> <h1 class="mui-title"><span id="name"></span></h1> </div> </header> <pre id='h'></pre> <script id='msg-template' type="text/template"> <% for(var i in record){ var item=record[i]; %> <div class="msg-item <%= (item.sender=='self'?' msg-item-self':'') %>" msg-type='<%=(item.type)%>' msg-content='<%=(item.content)%>'> <div style="height: 30px;text-align: center;font-size: small;color: #a6a6a6;"><%=item.addtime %></div> <% if(item.sender=='self' ) { %> <!--<i class="msg-user mui-icon mui-icon-person"></i>--> <img class="msg-my-img" src="<%=item.upic%>" alt="" /> <% } else { %> <img class="msg-user-img" src="<%=item.upic%>" alt="" /> <% } %> <div class="msg-content"> <div class="msg-content-inner"> <% if(item.type=='text' ) { %> <%=( item.content|| ' ') %> <% } else if(item.type=='image' ) { %> <img class="msg-content-image" src="<%=(item.content)%>" style="max-width: 100px;" /> <% } else if(item.type=='sound' ) { %> <span class="mui-icon iconfont icon-yuyin" style="font-size: 18px;font-weight: bold;"></span> <span class="play-state">点击播放</span> <% } %> </div> <div class="msg-content-arrow"></div> </div> <div class="mui-item-clear"></div> </div> <% } %> </script> <div class="mui-content" style="padding-top:70px;"> <div id='msg-list'> </div> </div> <footer> <div class="footer-left"> <i id='msg-image' class="mui-icon iconfont icon-paizhao" style="font-size: 28px;"></i> </div> <div class="footer-center"> <textarea id='msg-text' type="text" class='input-text'></textarea> <button id='msg-sound' type="button" class='input-sound' style="display: none;">按住说话</button> </div> <label for="" class="footer-right"> <i id='msg-type' class="mui-icon-paperplane"></i> <!--<i id='msg-type' class="mui-icon mui-icon-mic"></i>--> </label> </footer> <div id='sound-alert' class="rprogress"> <div class="rschedule"></div> <div class="r-sigh">!</div> <div id="audio_tips" class="rsalert">手指上滑,取消发送</div> </div> <script src="js/mui.min.js"></script> <script src="js/mui.imageViewer.js"></script> <script src="js/arttmpl.js"></script> <script src="js/db.js"></script>//创建数据库的一些操作 <script src="js/login.js" type="text/javascript" charset="utf-8"></script>//登录成功后记录的一些个人信息 <script src="http://10.0.1.0:65535/socket.io/socket.io.js"></script>//服务端 <script type="text/javascript" charset="utf-8"> mui.init({ beforeback:function(){ localStorage.chartitem="none"; } }) var ws=null; var code,name,onlineUsers2; //var bindMsgList; (function($, doc) { var MIN_SOUND_TIME = 800; $.init({ gestureConfig: { tap: true, //默认为true doubletap: true, //默认为false longtap: true, //默认为false swipe: true, //默认为true drag: true, //默认为true hold: true, //默认为false,不监听 release: true //默认为false,不监听 } }); template.config('escape', false); $.plusReady(function() { //去掉滚动条 plus.webview.currentWebview().setStyle({ scrollIndicator: 'none' }); ws = plus.webview.currentWebview(); code = ws.account;//警号 name=ws.name;//姓名 localStorage.chartitem="show"; document.getElementById("name").innerText=plus.webview.currentWebview().name; plus.webview.currentWebview().setStyle({ softinputMode: "adjustResize" }); var showKeyboard = function() { if ($.os.ios) { var webView = plus.webview.currentWebview().nativeInstanceObject(); webView.plusCallMethod({ "setKeyboardDisplayRequiresUserAction": false }); } else { var Context = plus.android.importClass("android.content.Context"); var InputMethodManager = plus.android.importClass("android.view.inputmethod.InputMethodManager"); var main = plus.android.runtimeMainActivity(); var imm = main.getSystemService(Context.INPUT_METHOD_SERVICE); imm.toggleSoftInput(0, InputMethodManager.SHOW_FORCED); //var view = ((ViewGroup)main.findViewById(android.R.id.content)).getChildAt(0); imm.showSoftInput(main.getWindow().getDecorView(), InputMethodManager.SHOW_IMPLICIT); } }; var record =[]; var ui = { body: doc.querySelector('body'), footer: doc.querySelector('footer'), footerRight: doc.querySelector('.footer-right'), footerLeft: doc.querySelector('.footer-left'), btnMsgType: doc.querySelector('#msg-type'), boxMsgText: doc.querySelector('#msg-text'), boxMsgSound: doc.querySelector('#msg-sound'), btnMsgImage: doc.querySelector('#msg-image'), areaMsgList: doc.querySelector('#msg-list'), boxSoundAlert: doc.querySelector('#sound-console.log'), h: doc.querySelector('#h'), content: doc.querySelector('.mui-content') }; ui.h.style.width = ui.boxMsgText.offsetWidth + 'px'; //console.log(ui.boxMsgText.offsetWidth ); var footerPadding = ui.footer.offsetHeight - ui.boxMsgText.offsetHeight; var msgItemTap = function(msgItem, event) { var msgType = msgItem.getAttribute('msg-type'); var msgContent = msgItem.getAttribute('msg-content') if (msgType == 'sound') { player = plus.audio.createPlayer(msgContent); var playState = msgItem.querySelector('.play-state'); playState.innerText = '正在播放...'; player.play(function() { playState.innerText = '点击播放'; }, function(e) { playState.innerText = '点击播放'; }); } }; var imageViewer = new $.ImageViewer('.msg-content-image', { dbl: false }); var bindMsgList = function() { //绑定数据: ui.areaMsgList.innerHTML = template('msg-template', { "record": record }); var msgItems = ui.areaMsgList.querySelectorAll('.msg-item'); [].forEach.call(msgItems, function(item, index) { item.addEventListener('tap', function(event) { msgItemTap(item, event); }, false); }); imageViewer.findAllImage(); setTimeout(function(){ ui.areaMsgList.scrollTop = ui.areaMsgList.scrollHeight + ui.areaMsgList.offsetHeight; },500); }; bindMsgList(); window.addEventListener('resize', function() { ui.areaMsgList.scrollTop = ui.areaMsgList.scrollHeight + ui.areaMsgList.offsetHeight; }, false); var send = function(msg) { record.push(msg); bindMsgList(); }; var toRobot = function(info) { bindMsgList(); }; function msgTextFocus() { ui.boxMsgText.focus(); setTimeout(function() { ui.boxMsgText.focus(); }, 150); } //解决长按“发送”按钮,导致键盘关闭的问题; ui.footerRight.addEventListener('touchstart', function(event) { if (ui.btnMsgType.classList.contains('mui-icon-paperplane')) { msgTextFocus(); event.preventDefault(); } }); //解决长按“发送”按钮,导致键盘关闭的问题; ui.footerRight.addEventListener('touchmove', function(event) { if (ui.btnMsgType.classList.contains('mui-icon-paperplane')) { msgTextFocus(); event.preventDefault(); } }); ui.footerRight.addEventListener('release', function(event) { // if(ui.boxMsgText.value.length<1){ //mui.toast("近期开放"); return; } if (ui.btnMsgType.classList.contains('mui-icon-paperplane')) { //showKeyboard(); ui.boxMsgText.focus(); setTimeout(function() { ui.boxMsgText.focus(); }, 150); // event.detail.gesture.preventDefault(); //接收服务器端显示,取代本地显示 /*send({ sender: 'self', type: 'text', content: ui.boxMsgText.value.replace(new RegExp('\n', 'gm'), '<br/>') });*/ var content=ui.boxMsgText.value.replace(new RegExp('\n', 'gm'), '<br/>'); ui.boxMsgText.value = ''; $.trigger(ui.boxMsgText, 'input', null); //console.log(plus.webview.currentWebview().account+"ee"); //同步内容 CHAT.submit(content,plus.webview.currentWebview().account);//接收者 } else if (ui.btnMsgType.classList.contains('icon-yuyin')) { ui.btnMsgType.classList.add('icon-xiepinglun'); ui.btnMsgType.classList.remove('icon-yuyin'); ui.boxMsgText.style.display = 'none'; ui.boxMsgSound.style.display = 'block'; ui.boxMsgText.blur(); document.body.focus(); } else if (ui.btnMsgType.classList.contains('icon-xiepinglun')) { ui.btnMsgType.classList.add('icon-yuyin'); ui.btnMsgType.classList.remove('icon-xiepinglun'); ui.boxMsgSound.style.display = 'none'; ui.boxMsgText.style.display = 'block'; //-- //showKeyboard(); ui.boxMsgText.focus(); setTimeout(function() { ui.boxMsgText.focus(); }, 150); } }, false); ui.footerLeft.addEventListener('tap', function(event) { if(onlineUsers2.hasOwnProperty(code)){ var btnArray = [{ title: "拍照" }, { title: "从相册选择" }]; plus.nativeUI.actionSheet({ title: "选择照片", cancel: "取消", buttons: btnArray }, function(e) { var index = e.index; switch (index) { case 0: break; case 1: var cmr = plus.camera.getCamera(); cmr.captureImage(function(path) { var dstname = "_downloads/" + getUid() + ".jpg"; compressImage(path, dstname); plus.nativeUI.showWaiting( "正在压缩图片" ); getNewUrl(); // send({ // sender: 'self', // type: 'image', // content: "file://" + plus.io.convertLocalFileSystemURL(path) // }); }, function(err) {}); break; case 2: plus.gallery.pick(function(path) { var dstname = "_downloads/" + getUid() + ".jpg"; compressImage(path, dstname); plus.nativeUI.showWaiting( "正在压缩图片" ); getNewUrl(); // }, function(err) { }, { filter: "image" }); break; } }); } else{ mui.toast("对方不在线"); } }, false); var files = []; var newUrlAfterCompress; function getNewUrl(){ if(newUrlAfterCompress!=undefined){ //console.log("转换后图片:"+newUrlAfterCompress); appendFile(newUrlAfterCompress); plus.nativeUI.showWaiting( "正在上传图片" ); upload(); } else{ setTimeout(getNewUrl,300); } } // 上传文件 function upload() { //var wt = plus.nativeUI.showWaiting(); var task = plus.uploader.createUpload(server + "?action=testupload", { method: "POST" }, function(t, status) { //上传完成 if (status == 200) { //mui.toast("图片上传成功"); var imgurl=t.responseText; var userimg=plus.storage.getItem("userimg"); if(userimg.length>3){ } else{ userimg="img/logo.png"; } // console.log(imgurl); var obj = { send: plus.storage.getItem("loginname"),//this.userid, username: plus.storage.getItem("loginname"),//this.username, content: imgurl, contentType:'image', receive:code, groupid:'0', uname:plus.storage.getItem("realname"), upic:userimg, type:'self' }; //plus.webview.currentWebview().groupid files = []; newUrlAfterCompress=undefined; this.socket = io.connect('ws://121.40.205.128:3000'); this.socket.emit('message', obj); plus.nativeUI.closeWaiting(); //wt.close(); } else { console.log("上传失败:" + status); } } ); for (var i = 0; i < files.length; i++) { var f = files[i]; // console.log("准备上传的图片路径:"+f.path); task.addFile(f.path, { key: f.name }); } task.start(); } function appendFile(p) { files.push({ name: "uploadkey",//服务端接收<span style="font-family: Arial, Helvetica, sans-serif;">uploadkey,再转存为图片就行了</span> path: p }); } // 产生一个随机数 function getUid() { return Math.floor(Math.random() * 100000000 + 10000000).toString(); } //压缩图片 function compressImage(src, dstname) { //var dstname="_downloads/"+getUid()+".jpg"; plus.zip.compressImage({ src: src, dst: dstname, overwrite: true, quality: 20//图片压缩 }, function(event) { //console.log("Compress success:"+event.target); newUrlAfterCompress=event.target; return event.target; }, function(error) { console.log(error); return src; //alert("Compress error!"); }); } var setSoundAlertVisable=function(show){ if(show){ ui.boxSoundAlert.style.display = 'block'; ui.boxSoundAlert.style.opacity = 1; }else{ ui.boxSoundAlert.style.opacity = 0; //fadeOut 完成再真正隐藏 setTimeout(function(){ ui.boxSoundAlert.style.display = 'none'; },200); } }; var recordCancel = false; var recorder = null; var audio_tips = document.getElementById("audio_tips"); var startTimestamp = null; var stopTimestamp = null; var stopTimer = null; ui.boxMsgSound.addEventListener('hold', function(event) { recordCancel = false; if(stopTimer)clearTimeout(stopTimer); audio_tips.innerHTML = "手指上划,取消发送"; ui.boxSoundAlert.classList.remove('rprogress-sigh'); setSoundAlertVisable(true); recorder = plus.audio.getRecorder(); if (recorder == null) { plus.nativeUI.toast("不能获取录音对象"); return; } startTimestamp = (new Date()).getTime(); recorder.record({ filename: "_doc/audio/" }, function(path) { if (recordCancel) return; send({ sender: 'self', type: 'sound', content: path }); }, function(e) { plus.nativeUI.toast("录音时出现异常: " + e.message); }); }, false); ui.body.addEventListener('drag', function(event) { //console.log('drag'); if (Math.abs(event.detail.deltaY) > 50) { if (!recordCancel) { recordCancel = true; if (!audio_tips.classList.contains("cancel")) { audio_tips.classList.add("cancel"); } audio_tips.innerHTML = "松开手指,取消发送"; } } else { if (recordCancel) { recordCancel = false; if (audio_tips.classList.contains("cancel")) { audio_tips.classList.remove("cancel"); } audio_tips.innerHTML = "手指上划,取消发送"; } } }, false); ui.boxMsgSound.addEventListener('release', function(event) { //console.log('release'); if (audio_tips.classList.contains("cancel")) { audio_tips.classList.remove("cancel"); audio_tips.innerHTML = "手指上划,取消发送"; } // stopTimestamp = (new Date()).getTime(); if (stopTimestamp - startTimestamp < MIN_SOUND_TIME) { audio_tips.innerHTML = "录音时间太短"; ui.boxSoundAlert.classList.add('rprogress-sigh'); recordCancel = true; stopTimer=setTimeout(function(){ setSoundAlertVisable(false); },800); }else{ setSoundAlertVisable(false); } recorder.stop(); }, false); ui.boxMsgSound.addEventListener("touchstart", function(e) { //console.log("start...."); e.preventDefault(); }); ui.boxMsgText.addEventListener('input', function(event) { ui.btnMsgType.classList['add']('mui-icon-paperplane'); ui.btnMsgType.setAttribute("for", ui.boxMsgText.value == '' ? '' : 'msg-text'); ui.h.innerText = ui.boxMsgText.value.replace(new RegExp('\n', 'gm'), '\n-') || '-'; ui.footer.style.height = (ui.h.offsetHeight + footerPadding) + 'px'; ui.content.style.paddingBottom = ui.footer.style.height; }); ui.boxMsgText.addEventListener('tap', function(event) { ui.boxMsgText.focus(); setTimeout(function() { ui.boxMsgText.focus(); }, 0); }, false); var conn=new DBConn(); //保存联系人表 function insertData(send,receive,content,uname){ var sql="select * from chart_list where send='"+send+"' and receive='"+receive+"'"; console.log("监听最近联系人"+sql); conn.executeScarl(sql, function(tx,result){ console.log("sql的结果集"+result.rows.length); if(result.rows.length>0){ //存在最近记录 sql="update chart_list set content='"+content+"' where send='"+send+"' and receive='"+receive+"'"; conn.executeSqlDefault(sql, [], function (tx, result) { //保存成功 }, function (tx, error) { console.log('记录保存失败: ' + error.message); } ); }else{ conn.executeScarl("select * from chart_list order by id desc limit 0,1", function(tx,result){ /*var id=0; if(result.rows.length>0){ id=parseInt(result.rows.item(0)["id"])+1; }else{ id=1; }*/ //添加最近记录,判断是否存在记录,无责为1,否则为最大值+1 var da=new Date(); var adddate=da.getFullYear()+"-"+(da.getMonth()+1)+"-"+da.getDay()+" "+da.getHours()+":"+da.getMinutes()+":"+da.getSeconds(); sql="insert into chart_list (send,receive,addtime,content,groupid,uname) values('"+send+"','"+receive+"','"+adddate+"','"+content+"',0,'"+uname+"')"; //console.log(sql); conn.executeSqlDefault(sql, [], function (tx, result) { //保存成功 }, function (tx, error) { console.log('记录保存失败: ' + error.message); } ); } ) } },function(tx,error){ console.log(error); } ); } //保存聊天内容表 function insertDataContent(id,send,receive,adddate,content,contentType,type,upic){ conn.executeScarl("select * from chart_list_content order by addtime desc limit 0,1", function(tx,result){ var type=""; if(plus.storage.getItem("loginname")==send){ type='self'; }else{ type='send'; } //添加最近记录,判断是否存在记录,无责为1,否则为最大值+1 var sql="insert into chart_list_content (id,send,receive,addtime,content,contentType,type,isread,upic) values('"+id+"','"+send+"','"+receive+"','"+adddate+"','"+content+"','"+contentType+"','"+type+"',1,'"+upic+"')"; // console.log(sql); //console.log(sql+"ee"); conn.executeSqlDefault(sql, [], function (tx, result) { //保存成功 record.push({ sender: type, type: contentType, content: content, addtime:adddate, upic:upic }); bindMsgList(); }, function (tx, error) { console.log('记录保存失败: ' + error.message); } ); } ) } //群组-------------------------- //保存联系人表 function insertGroupData(send,receive,content,groupid,gname,pic){ var sql=""; conn.executeScarl("select * from chart_list where groupid='"+groupid+"'", function(tx,result){ if(result.rows.length>0){ //存在最近记录 sql="update chart_list set content='"+content+"' where groupid='"+groupid+"'"; conn.executeSqlDefault(sql, [], function (tx, result) { //保存成功 }, function (tx, error) { console.log('记录保存失败: ' + error.message); } ); }else{ conn.executeScarl("select * from chart_list order by addtime desc limit 0,1", function(tx,result){ /*var id=0; if(result.rows.length>0){ id=parseInt(result.rows.item(0)["id"])+1; }else{ id=1; }*/ //添加最近记录,判断是否存在记录,无责为1,否则为最大值+1 var da=new Date(); var adddate=da.getFullYear()+"-"+(da.getMonth()+1)+"-"+da.getDay()+" "+da.getHours()+":"+da.getMinutes()+":"+da.getSeconds(); sql="insert into chart_list (send,receive,addtime,content,groupid,uname,gname,pic) values('','','"+adddate+"','"+content+"','"+groupid+"','','"+gname+"','"+pic+"')"; // console.log(sql); conn.executeSqlDefault(sql, [], function (tx, result) { //保存成功 }, function (tx, error) { console.log('记录保存失败: ' + error.message); } ); } ) } } ); } //保存群组聊天内容表 function insertDataGroupContent(id,send,receive,adddate,content,contentType,type,groupid){ conn.executeScarl("select * from chart_group_list_content order by addtime desc limit 0,1", function(tx,result){ var type=""; if(plus.storage.getItem("loginname")==send){ type='self'; }else{ type='send'; } //添加最近记录,判断是否存在记录,无责为1,否则为最大值+1 var sql="insert into chart_group_list_content (id,send,content,contentType,addtime,type,groupid) values('"+id+"','"+send+"','"+content+"','"+contentType+"','"+adddate+"','"+type+"',"+groupid+")"; //console.log(sql); conn.executeSqlDefault(sql, [], function (tx, result) { //保存成功 //initList(); }, function (tx, error) { console.log('记录保存失败: ' + error.message); } ); } ) } //显示本地聊天信息 function initData(){ //conn.executeScarl("select * from chart_list_content where (send='"+plus.webview.currentWebview().account+"' or send='"+plus.storage.getItem("loginname")+"') and (receive='"+plus.storage.getItem("loginname")+"' or receive='"+plus.webview.currentWebview().account+"') order by id asc limit 0,100", conn.executeScarl("select * from chart_list_content where (send='"+plus.webview.currentWebview().account+"' and receive='"+plus.storage.getItem("loginname")+"') or (send='"+plus.storage.getItem("loginname")+"' and receive='"+plus.webview.currentWebview().account+"') order by id asc limit 0,100", function(tx,result){ if(result.rows.length>0){ for(var i=0;i<result.rows.length;i++){ record.push({ sender: result.rows.item(i)["type"], type: result.rows.item(i)["contentType"], content: result.rows.item(i)["content"], addtime:result.rows.item(i)["addtime"], groupid:0, upic:result.rows.item(i)["upic"] }); bindMsgList(); } } }); }; initData(); var d = document, w = window, p = parseInt, dd = d.documentElement, db = d.body, dc = d.compatMode == 'CSS1Compat', dx = dc ? dd: db, ec = encodeURIComponent; w.CHAT = { msgObj:d.getElementById("message"), screenheight:w.innerHeight ? w.innerHeight : dx.clientHeight, username:null, userid:null, socket:null, onlineUsers:null, reivice:null, //让浏览器滚动条保持在最低部 scrollToBottom:function(){ //w.scrollTo(0, this.msgObj.clientHeight); }, //退出,本例只是一个简单的刷新 logout:function(){ //this.socket.disconnect(); //location.reload(); }, //提交聊天消息内容 submit:function(content,reivicer){ var content = content; if(content != ''){ var arrUserList; // var arrUserList=onlineUsers.split('、'); if(onlineUsers2.hasOwnProperty(reivicer)){ var userimg=plus.storage.getItem("userimg"); if(userimg.length<1){ userimg="img/logo.png"; } var obj = { send: plus.storage.getItem("loginname"),//this.userid, username: plus.storage.getItem("loginname"),//this.username, content: content, contentType:'text', receive:reivicer, groupid:0, type:'self', uname:plus.storage.getItem("realname"), upic:userimg }; this.socket = io.connect('ws://121.40.205.128:3000'); this.socket.emit('message', obj); } else{ mui.toast("对方不在线"); return false; } // console.log(arrUserList); } return false; }, genUid:function(){ return new Date().getTime()+""+Math.floor(Math.random()*899+100); }, //更新系统消息,本例中在用户加入、退出的时候调用 updateSysMsg:function(o, action){ //当前在线用户列表 onlineUsers2 = o.onlineUsers; //当前在线人数 var onlineCount = o.onlineCount; //新加入用户的信息 var user = o.user; //更新在线人数 var userhtml = ''; var separator = ''; // for(key in onlineUsers) { // if(onlineUsers2.hasOwnProperty(key)){ // userhtml += separator+onlineUsers[key]; // separator = '、'; // } // } }, //第一个界面用户提交用户名 usernameSubmit:function(){ return false; }, init:function(){ /* 客户端根据时间和随机数生成uid,这样使得聊天室用户名称可以重复。 实际项目中,如果是需要用户登录,那么直接采用用户的uid来做标识就可以 */ this.userid = plus.storage.getItem("loginname"); this.username = plus.storage.getItem("loginname"); //连接websocket后端服务器 this.socket = io.connect('ws://121.40.205.128:3000'); //告诉服务器端有用户登录 this.socket.emit('login', {userid:this.userid, username:this.username}); //监听新用户登录 this.socket.on('login', function(o){ CHAT.updateSysMsg(o, 'login'); }); //监听用户退出 this.socket.on('logout', function(o){ CHAT.updateSysMsg(o, 'logout'); }); //监听消息发送 this.socket.on('message', function(obj){ //监听服务器发送的消息,保存到本地,然后展示 // console.log("监听时收到的obj.groupid"+obj.groupid); if(obj.groupid==0){ conn.executeScarl("select * from chart_list_content where id='"+obj.id+"'", function(tx,result){ //单人聊天监听保存 conn.executeScarl("select * from chart_list_content where id='"+obj.id+"'", function(tx,result){ if(result.rows.length==0){ var send=""; if(obj.send==plus.storage.getItem("loginname")){ send=obj.receive; }else{ send=obj.send; } //insertData(send,receive,content,uname) insertData(send,plus.storage.getItem("loginname"),obj.content,obj.uname); insertDataContent(obj.id,obj.send,obj.receive,obj.addtime,obj.content,obj.contentType,obj.type,obj.upic); } }); }); }else{ //群组聊天监听保存 conn.executeScarl("select * from chart_group_list_content where id='"+obj.id+"'", function(tx,result){ if(result.rows.length==0){ var send=""; if(obj.send==plus.storage.getItem("loginname")){ send=obj.receive; }else{ send=obj.send; } if(localStorage.chartitem!="show"){ }else{ //initList(); //insertGroupData(send,receive,content,groupid,gname,pic){ insertGroupData(send,plus.storage.getItem("loginname"),obj.content,obj.groupid,"",plus.storage.getItem("userimg")); insertDataGroupContent(obj.id,obj.send,obj.receive,obj.addtime,obj.content,obj.contentType,obj.type,1); } } }); } }); this.socket.on('notline', function(obj){ mui.toast("对方不在线"); }); } }; CHAT.init(); }); }(mui, document)); </script> </body> </html>
服务端接收图片,并返回网络路径:
int l = Request.Files["uploadkey"].ContentLength; byte[] buffer = new byte[l]; Stream s = Request.Files["uploadkey"].InputStream; //string imgtype = Request.Files[3 + i].ContentType; //image/png System.Drawing.Bitmap image = new System.Drawing.Bitmap(s); string imgname = Common.GetGuid() + ".jpg"; string path = "Images/" + DateTime.Now.ToString("yyyyMMdd"); if (!Directory.Exists(HttpContext.Current.Server.MapPath(path))) { System.IO.Directory.CreateDirectory(HttpContext.Current.Server.MapPath(path)); } string newurl=Server.MapPath(path + "/" + imgname); image.Save(newurl);
以上是关于H5+MUI+Node.js+Socket.io实现即时聊天以及发送+图片压缩的主要内容,如果未能解决你的问题,请参考以下文章
未找到 Socket.io.js(node.js + express + socket.io)
Node.js - Socket.io:socket.request 未定义
HTTP 状态代码 200 但页面未加载 Node.js Socket.io -- 使用 Socket.io 的 Node.js 教程,Daniel Nill,fs.readFile(),socket