内容简介:前段时间写了一个小程序即时聊天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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。