内容简介:前段时间写了一个小程序即时聊天demo,仿微信,效果如下:项目地址是:大家可以自行下载,按照提示运行,就能看到效果;现在只是做了要给基本版的,要做复杂功能,可以继续添加。
前段时间写了一个小程序即时聊天demo,仿微信,效果如下:
项目地址是: github.com/lirongrong/… ,
大家可以自行下载,按照提示运行,就能看到效果;现在只是做了要给基本版的,要做复杂功能,可以继续添加。
功能
- 发送文字
- 发送图片(图片可点击放大)
- 发送拍摄照片 (图片可点击放大)
- 发送位置 (map组件默认在最顶层,样式控制不了,bug还在修复中...)
- 发送语音 (包括语音时长,可点击播放)
websorket长连接
是基于nodejs-websocket的服务,代码如下:(最基础版)
var ws = require("nodejs-websocket") // Scream server example: "hi" -> "HI!!!" //创建一个server var server = ws.createServer(function (conn) { console.log("New connection") conn.on("text", function (str) { // console.log("Received "+str) // conn.sendText(str.toUpperCase()+"!!!") //链接成功之后,发送欢迎语 console.log("连接成功") //欢迎语 if(str == 'null'){ conn.sendText("有什么能帮到您?"); } //输入文字 else if(str != 'null' && str){ conn.sendText("文字") } //输入多媒体 else{ conn.sendText("多媒体文本") } console.log(str); }) conn.on("close", function (code, reason) { console.log("Connection closed") }) }).listen(8001) 复制代码
在项目根目录下运行 npm run dev
服务就能启动了, 启动之后websorket地址为: ws://localhost:8001
chat.js
直接看代码,注释都写清楚了
// pages/user/chat.js var util = require('../utils/util.js'); var app = getApp(); //websocket心跳重连对象 let heartCheck = { timeout: 1000,//1s timeoutObj: null, serverTimeoutObj: null, //重置 reset: function () { clearTimeout(this.timeoutObj); clearTimeout(this.serverTimeoutObj); return this; }, //开始 start: function () { wx.sendSocketMessage({ data: "null", }); }, }; //微信小程序新录音接口,录出来的是aac或者mp3,这里要录成mp3 const recorderManager = wx.getRecorderManager(); const options = { duration: 600000,//录音时长,这里设置的是最大值10分钟 sampleRate: 44100, numberOfChannels: 1, encodeBitRate: 192000, format: 'mp3', //frameSize: 50 }; //音频播放 const innerAudioContext = wx.createInnerAudioContext() Page({ data: { taskId:'', userId:'', chatList:[],//聊天内容 isShowModelUp:false,//底部弹框显示true,隐藏为false isLuYin:false,//没有录音false,开始录音true luYinText:'按住说话', audioUrl:'',//录音文件地址 isShowLuYin:false,//true为开始播放,false为取消播放 inputValue:'',//输入框内容 lockReconnect:false,//默认进来是断开链接的 limit:0,//重连次数 }, onLoad: function (options) { this.linkSocket(); }, //连接socket linkSocket:function(){ let that = this; wx.connectSocket({ //url: app.globalData.wsUrl + 'websocket?' + this.data.taskId + '&' + this.data.userId, url:app.globalData.wsUrl, success() { console.log('连接成功') wx.onSocketMessage((res) => { console.log(res.data); //收到消息 that.pushChatList(0, { text: res.data }); }) wx.onSocketOpen(() => { console.log('WebSocket连接打开') heartCheck.reset().start() }) wx.onSocketError(function (res) { console.log('WebSocket连接打开失败') that.reconnect() }) wx.onSocketClose(function (res) { console.log('WebSocket已关闭!') that.reconnect() }) } }) }, //断线重连 reconnect() { var that = this; if (that.lockReconnect) return; that.lockReconnect = true; clearTimeout(that.timer) if (that.data.limit < 12) { that.timer = setTimeout(() => { that.linkSocket(); that.lockReconnect = false; }, 5000); that.setData({ limit: that.data.limit + 1 }) } }, //打开底部弹框 showModelUp:function(){ var that=this; if (that.data.isShowModelUp==false){ that.setData({ isShowModelUp: true, }) }else{ that.setData({ isShowModelUp: false, }) } }, //关闭底部弹框 closeModelUp:function(){ var that=this; that.setData({ isShowModelUp:false, }) }, //选择照片 chooseImage:function(){ var that=this; wx.chooseImage({ count: 1, // 默认9 sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有 sourceType: ['album'], // 可以指定来源是相册还是相机,默认二者都有 success: function (res) { // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片 var tempFilePaths = res.tempFilePaths; console.log(res); that.pushChatList(1,{ imgUrl: tempFilePaths, }) //关闭弹窗 that.closeModelUp(); that.pageScrollToBottom(); } }) }, //界面滚到最底端 pageScrollToBottom: function () { wx.createSelectorQuery().select('#bottom').boundingClientRect(function (rect) { console.log(rect.top); console.log(rect.bottom); // 使页面滚动到底部 wx.pageScrollTo({ scrollTop: rect.bottom + 200 }) }).exec() }, //预览图片 previewImage:function(e){ console.log(e); var url=e.currentTarget.dataset.src; var that=this; wx.previewImage({ current: url[0], // 当前显示图片的http链接 urls: url // 需要预览的图片http链接列表 }) }, //拍摄 paishe:function(){ var that = this; wx.chooseImage({ count: 1, // 默认9 sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有 sourceType: ['camera'], // 可以指定来源是相册还是相机,默认二者都有 success: function (res) { // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片 var tempFilePaths = res.tempFilePaths; console.log(res); that.pushChatList(1,{ imgUrl: tempFilePaths, }) //关闭弹窗 that.closeModelUp(); that.pageScrollToBottom(); } }) }, //发送位置 getlocat: function () { var that = this wx.getLocation({ type: 'gcj02', //返回可以用于wx.openLocation的经纬度 success: function (res) { that.setData({ latitude: res.latitude, longitude: res.longitude, markers: [{ latitude: res.latitude, longitude: res.longitude, name: '时代一号', desc: '现在的位置' }], }) that.pushChatList(1,{ map: true }) } }) that.closeModelUp(); that.pageScrollToBottom(); }, //切换是否录音按钮 btnRecord:function(){ var that=this; if (that.data.isLuYin==false){ that.setData({ isLuYin: true }); }else{ that.setData({ isLuYin: false, luYinText: '按住说话' }); } }, //开始录音 startRecord:function(e){ var that=this; that.setData({ luYinText:'录音中...', }); recorderManager.start(options); recorderManager.onStart(() => { console.log('recorder start') }) }, //结束录音 stopRecord:function(){ var that = this; that.setData({ luYinText: '按住说话' }); recorderManager.stop(); recorderManager.onStop((res) => { console.log('recorder stop', res) const { tempFilePath } = res; that.pushChatList(1,{ audioUrl: res.tempFilePath, audioDuration: (res.duration / 60000).toFixed(2),//录音时长,转为分,向后取两位, }) that.setData({ audioUrl: res.tempFilePath, audioDuration: (res.duration / 60000).toFixed(2),//录音时长,转为分,向后取两位, }) }) //关闭弹窗 that.closeModelUp(); that.pageScrollToBottom(); }, //录音、停止播放 playRecord:function(e){ console.log(e); var that=this; innerAudioContext.autoplay = true; innerAudioContext.src = that.data.audioUrl //innerAudioContext.src = 'http://ws.stream.qqmusic.qq.com/M500001VfvsJ21xFqb.mp3?guid=ffffffff82def4af4b12b3cd9337d5e7&uin=346897220&vkey=6292F51E1E384E061FF02C31F716658E5C81F5594D561F2E88B854E81CAAB7806D5E4F103E55D33C16F3FAC506D1AB172DE8600B37E43FAD&fromtag=46';//测试音频文件 if (!e.currentTarget.dataset.isshowluyin){//开始播放 //innerAudioContext.play();//兼容起见用它 innerAudioContext.onPlay(() => { console.log('开始播放'); that.setData({ isShowLuYin: true }); return; }); }else{//暂停播放 innerAudioContext.pause(); console.log("暂停"); that.setData({ isShowLuYin: false }); return; } }, //输入框点击完成按钮时触发 btnConfirm:function(e){ var that = this; if (typeof (e) == 'undefined' || e.detail.value == ''){ return false; }else { var value = e.detail.value; that.pushChatList(1,{ text: value }); that.setData({ inputValue:''//清空输入框 }) //发送数据 wx.sendSocketMessage({ data: value }) //关闭弹窗 that.closeModelUp(); that.pageScrollToBottom(); } }, //页面隐藏/切入后台时触发 onHide:function(){ wx.onSocketClose(function (res) { console.log('WebSocket已关闭!') }) }, //页面卸载时触发 onUnload:function(){ wx.onSocketClose(function (res) { console.log('WebSocket已关闭!') }) }, //pushchatList //enu:0 是客服发送的消息 //enu:1 是我发送的消息 pushChatList:function(enu,options){ var that = this; var defaults = { userImage: '', text: '', isAdmin: false, } options = util.extendObj(defaults,options); options.time = util.formatDateTime(util.getNowFormatDate()); console.log(options); if(enu == 0){ options.userImage = '../images/admin.png'; options.isAdmin = false; }else if(enu==1){ options.userImage = app.globalData.wxUserInfo.avatarUrl; options.isAdmin = true; } var t = that.data.chatList; t.push(options) that.setData({ chatList: t }); } }) 复制代码
需要优化的地方
- 上传图片应该要支持多图上传并压缩一下,我做h5的聊天功能的时候压缩了,这个简版的小程序没做,大家可以自行加上
- 这个demo只是实现了UI和文字的通讯,图片、视频、地图等的通讯还没完善
- 发送消息之后滚到底部的方法需要改进,因为发送图片、地图、语音没有滚到底部
- 需要改进的请大神指点
以上所述就是小编给大家介绍的《小程序即时通讯demo》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
凸优化
Stephen Boyd、Lieven Vandenberghe / 王书宁、许鋆、黄晓霖 / 清华大学出版社 / 2013-1 / 99.00元
《信息技术和电气工程学科国际知名教材中译本系列:凸优化》内容非常丰富。理论部分由4章构成,不仅涵盖了凸优化的所有基本概念和主要结果,还详细介绍了几类基本的凸优化问题以及将特殊的优化问题表述为凸优化问题的变换方法,这些内容对灵活运用凸优化知识解决实际问题非常有用。应用部分由3章构成,分别介绍凸优化在解决逼近与拟合、统计估计和几何关系分析这三类实际问题中的应用。算法部分也由3章构成,依次介绍求解无约束......一起来看看 《凸优化》 这本书的介绍吧!