小程式即時通訊demo
專案地址是: ofollow,noindex">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和文字的通訊,圖片、視訊、地圖等的通訊還沒完善
- 傳送訊息之後滾到底部的方法需要改進,因為傳送圖片、地圖、語音沒有滾到底部
- 需要改進的請大神指點