Some time ago wrote a small program instant chat demo, imitation wechat, the effect is as follows:

The project address is: github.com/lirongrong/… .

You can download, follow the prompts to run, you can see the effect; Now we just do the basic version, to do complex features, you can continue to add.

function

  1. Send text
  2. Send pictures (click to enlarge pictures)
  3. Send photos (click to enlarge picture)
  4. Send location (map component is on top by default, style control is not available, bug is still being fixed…)
  5. Voice sending (including voice duration, click Play)

Websorket long connection

Nodejs-websocket is a nodejs-websocket service with the following code :(basic version)

var ws = require("nodejs-websocket")

// Scream server example: "hi" -> "HI!!!"Var server = ws.createserver (function (conn) {
	console.log("New connection")
	conn.on("text".function (str) { 
		// console.log("Received "+str)
		// conn.sendText(str.toUpperCase()+"!!!"// After the link is successful, send the welcome message console.log("Connection successful"(// Welcome wordsif(str == 'null'){
			conn.sendText("How can I help you?"); } // Enter textelse if(str ! ='null' && str){
			conn.sendText("Text"} // Enter multimediaelse{
			conn.sendText("Multimedia Text")
		}
		console.log(str);
	})
	conn.on("close".function (code, reason) {
		console.log("Connection closed")
	})
}).listen(8001)
Copy the code

The websorket address is ws://localhost:8001. The websorket address is ws://localhost:8001

chat.js

Look directly at the code, the comments are written clearly

// pages/user/chat.js
var util = require('.. /utils/util.js'); var app = getApp(); //websocket Heartbeat reconnection objectletHeartCheck = {timeout: 1000,//1s timeoutObj: null, serverTimeoutObj: null, // reset:function () {
    clearTimeout(this.timeoutObj);
    clearTimeout(this.serverTimeoutObj);
    returnthis; }, // start start:function () {
    wx.sendSocketMessage({
      data: "null"}); }}; Const recorderManager = wx.getRecorderManager(); const recorderManager = wx.getRecorderManager(); Duration: 600000,// Maximum recording duration 10 minutes sampleRate: 44100, numberOfChannels: 1, encodeBitRate: 192000, format:'mp3', //frameSize: 50 }; / / audio playback const innerAudioContext = wx. CreateInnerAudioContext () Page ({data: {taskId:' ',
    userId:' '[],// isShowModelUp:false// The bottom pop-up box is displayedtrue, hidden forfalse 
    isLuYin:false// There is no recordingfalse, start recordingtrue
    luYinText:'Hold and speak',
    audioUrl:' '// The recording file address isShowLuYin:false, / /trueTo start playing,falseTo unplay inputValue:' ',// Input box content lockReconnect:false// The link is broken by defaultlimit}, onLoad:function(options) { this.linkSocket(); }, // connect to socket:function() {let that = this;
    wx.connectSocket({
      //url: app.globalData.wsUrl + 'websocket? ' + this.data.taskId + '&' + this.data.userId,
      url:app.globalData.wsUrl,
      success() {
        console.log('Connection successful') wx.onSocketMessage((res) => { console.log(res.data); PushChatList (0, {text: res.data}); }) wx.onSocketOpen(() => { console.log('WebSocket connection open ')
          heartCheck.reset().start()
        })
        wx.onSocketError(function (res) {
          console.log('WebSocket connection failed to open ')
          that.reconnect()
        })
        wx.onSocketClose(function (res) {
          console.log('WebSocket closed! ') that. Reconnect ()})}, // 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})}}, // Open the bottom box showModelUp:function(){ 
    var that=this; 
    if (that.data.isShowModelUp==false){
      that.setData({
        isShowModelUp: true})},else{
      that.setData({
        isShowModelUp: false})}}, // Close the bottom popup closeModelUp:function(){
    var that=this;
    that.setData({
      isShowModelUp:false})}, // Select photo chooseImage:function(){ var that=this; Wx. chooseImage({count: 1, // default 9 sizeType: ['original'.'compressed'], // You can specify whether the image is original or compressed. By default, both are availablesourceType: ['album'], // You can specify whether the source is photo album or camera, and default to both success:functionVar tempFilePaths = res.tempfilepaths; (res) {// Returns the list of local file paths for the selected photos. console.log(res); PushChatList (1,{imgUrl: tempFilePaths,}) // Close popup that.closemodelUp (); that.pageScrollToBottom(); }})}, // The interface rolls to the bottom of the pageScrollToBottom:function () {
    wx.createSelectorQuery().select('#bottom').boundingClientRect(function(rect) { console.log(rect.top); console.log(rect.bottom); Wx.pagescrollto ({scrollTop: rect.bottom + 200})}).exec()},function(e){ console.log(e); var url=e.currentTarget.dataset.src; var that=this; Wx.previewimage ({current: url[0], // HTTP url of the current display image: url // HTTP link list of images to preview})}, // Paishe:function(){ var that = this; Wx. chooseImage({count: 1, // default 9 sizeType: ['original'.'compressed'], // You can specify whether the image is original or compressed. By default, both are availablesourceType: ['camera'], // You can specify whether the source is photo album or camera, and default to both success:functionVar tempFilePaths = res.tempfilepaths; (res) {// Returns the list of local file paths for the selected photos. console.log(res); PushChatList (1,{imgUrl: tempFilePaths,}) // Close popup that.closemodelUp (); that.pageScrollToBottom(); }})}, // send position getlocat:function () {
    var that = this
    wx.getLocation({
      type: 'gcj02', // Return latitude and longitude success that can be used for wx.openLocation:function (res) {
        that.setData({
          latitude: res.latitude,
          longitude: res.longitude,
          markers: [{
            latitude: res.latitude,
            longitude: res.longitude,
            name: Time One,
            desc: 'Current position'
          }], 
        })
        that.pushChatList(1,{
          map: true}) } }) that.closeModelUp(); that.pageScrollToBottom(); }, // Toggle whether record button btnRecord:function(){ 
    var that=this;
    if (that.data.isLuYin= =false){
      that.setData({
        isLuYin: true
      });
    }else{
      that.setData({
        isLuYin: false,
        luYinText: 'Hold and speak'}); }}, // Start recordingfunction(e){ 
    var that=this;
    that.setData({
      luYinText:'In the recording... '}); recorderManager.start(options); recorderManager.onStart(() => { console.log('recorder start'})}, // Stop recording:function(){ 
    var that = this;
    that.setData({
      luYinText: 'Hold and speak'
    });
    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),// Duration of recording, convert to minutes, take two digits back,}) that.setData({audioUrl: res.tempFilepath, audioDuration: (res.duration / 60000).tofixed (2),// Record duration, convert to minutes, take two digits back,})}) // Close popup that.closemodelup (); that.pageScrollToBottom(); }, // Stop 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=6292F51 E1E384E061FF02C31F716658E5C81F5594D561F2E88B854E81CAAB7806D5E4F103E55D33C16F3FAC506D1AB172DE8600B37E43FAD&fromtag=46'; // Test the audio fileif(! E.c. with our fabrication: urrentTarget. Dataset. Isshowluyin) {/ / play / / innerAudioContext. The play (); // Use it for compatibility innerAudioContext.onplay (() => {console.log()'Start playing');
        that.setData({ 
          isShowLuYin: true
        }); 
        return;
      }); 
    }else{// Pause playing innerAudioContext.pause(); console.log("Pause");
      that.setData({
        isShowLuYin: false
      });
      return; }}, // btnConfirm is triggered when the input box is clicked on the finish button: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:' 'SendSocketMessage ({data: value}) // Close the popover that.closemodelup (); that.pageScrollToBottom(); }}, // page hide/access to the background trigger onHide:function(){
    wx.onSocketClose(function (res) {
      console.log('WebSocket closed! ')})}, // When a page unloads, it triggers onUnload:function(){
    wx.onSocketClose(function (res) {
      console.log('WebSocket closed! '})}, //pushchatList //enu:0; //enu:1;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 }); }})Copy the code

Areas that need to be optimized

  1. Upload pictures should support multi picture upload and compression, I do H5 chat function compression, this simple version of the small program did not do, we can add their own
  2. This demo only realized UI and text communication, pictures, videos, maps and other communication is not perfect
  3. The method of rolling to the bottom after sending a message needs to be improved because sending pictures, maps, and voice messages does not roll to the bottom
  4. Need to improve please god guidance