前端微信小程序websocket实现即时聊天

今天给大家分享一下本人做小程序使用websocket的一点小经验,希望对大家有所帮助。

使用之前肯定首先要了解一下websocket是什么,简单来讲websocket就是客户端与服务器之间专门建立的一条特殊通道,请求只需要请求一次,而且还可以从通道实时获取服务器数据,非常适合应用到实时应用上。

因为这里本人是分享小程序,所以就不去深究websocket的底层和协议了,感兴趣的朋友可以去看下websocket协议

建议大家在做之前先看看微信小程序官方提供的api关于websocket的文档,因为微信的websocket接口虽然和HTML5的websocket基本一样但是语法上还是有少许偏差,了解一下还是很有必要的。

话不多说上代码(css代码就不贴了,就是一些简单的聊天样式排版)

wxml

    <view>
     <scroll-view scroll-y="true" scroll-with-animation="true" scroll-x="false" scroll-into-view="list-{
       {idx}}" class="twnav">
            <view class='twChild'>
            <!-- <text>视频聊天室</text> -->
            <view class='tellRoom'  wx:for="{
       {tellData}}" wx:for-index="idx" wx:for-item="li" wx:key="li" id='list-{
       {li.id}}'>
              <view class='myHead'>
                <image class='sayHead' wx-if='{
       {li.type=="question"||li.type=="message"}}' src='{
       {li.avatarurl}}'></image>
                <image class='sayHead' wx-if='{
       {li.type=="answer"}}' src='{
       {li.content.orgLogo}}'></image>
              </view>
              <view class='tellDetail'>
                  <text class='name' wx-if='{
       {li.type=="question"||li.type=="message"}}'>{
       {li.displayName}}:</text>
                  <text class='name' wx-if='{
       {li.type=="answer"}}'>{
       {li.content.orgName}}回复{
       {li.displayName}}:</text>
                  <view wx-if='{
       {li.type=="answer"}}' class='answer'>
                    <view class='anQue'>{
       {li.content.question}}</view>
                    <view class='anAn'>{
       {li.content.answer}}</view>
                  </view>
                  <image wx-if='{
       {li.type=="question"}}' class='question' src='../../image/icon_quiz@2x.png' mode='widthFix'></image>
                  <text class='sayDetail' wx-if='{
       {li.type=="question"}}'>{
       {li.content.content}}</text>
                  <text class='sayDetail' wx-if='{
       {li.type=="message"}}'>{
       {li.content}}</text>
              </view>
            </view>
            <view class='ccds'></view>
            </view>
      </scroll-view>
          <view class='btn' wx-if='{
       {tell==true&&promodal==false}}'>
              <form bindreset="foo">
                <input class="myinput"  placeholder="说点什么吧" bindinput="sayValue" focus='{
       {myinputing}}'/>
                <button form-type="reset" class='sub' wx-if='{
       {isSend=="send"||isSend=="sureAsk"}}'  bindtap='sendMes'>发送</button>
                <button form-type="reset" class='sub' wx-if='{
       {isSend=="ask"}}' bindtap='ask'>问</button>
              </form>
            </view>
       </view>

JS:

    const app = getApp()
    var server = app.globalData.myUrl//这是自己的服务端接口地址设置于app.js
    var WxParse = require('../../wxParse/wxParse.js');
    var tellPage = 1
    var myurl='ws://+"你自己的链接地址"'
    var ws     // socket发送的消息队列
    var socketMsgQueue = []
    var socketOpen = true            // 判断心跳变量
    var heart = ''                   // 心跳失败次数
    var heartBeatFailCount = 0       // 终止心跳
    var heartBeatTimeOut = null;     // 终止重新连接
    var connectSocketTimeOut = null;
    Page({
      /**
       * 页面的初始数据
       */
      data: {
        sayValue:'',
        tellData:[],//聊天消息
        idx:'',
        id:'',
        fjh:'',//房间号
        myinputing:'',
        isSend: 'ask',
      },
      /**
        * 生命周期函数--监听页面加载
        */
      onLoad: function (options) {
        this.setData({
          id: options.id,
          fjh:options.roomNum,
        })
       this.history(1)
       this.connectStart()
      },
      /**
       * 生命周期函数--监听页面初次渲染完成
       */
      onReady: function () {
        //监听websocket连接状态
          this.deal()
      },
      /**
       * 生命周期函数--监听页面显示
       */
      onShow: function () {
        console.log()
      },
      /**
       * 生命周期函数--监听页面隐藏
       */
      onHide: function () {
      },
      /**
       * 生命周期函数--监听页面卸载
       */
      onUnload: function () {
        var that = this
        //离开页面销毁websocket并恢复初始数据
        wx.closeSocket()
        twice = 0
        socketOpen = true
        heart = ''                   // 心跳失败次数
        heartBeatFailCount = 0       // 终止心跳
        heartBeatTimeOut = null;     // 终止重新连接
        connectSocketTimeOut = null;
      },
      /**
       * 页面相关事件处理函数--监听用户下拉动作
       */
      onPullDownRefresh: function () {
      },
      /**
       * 页面上拉触底事件的处理函数
       */
      onReachBottom: function () {
      },
      /**
       * 用户点击右上角分享
       */
      onShareAppMessage: function () {
        console.log('点击分享')
      },
      //获取聊天室历史记录
      history: function (a) {
        var that = this
        wx.request({
          url: server + 'api/message/chatmsg',
          header: {
            "Authorization": app.globalData.token,
          },
          data: {
            page: a,
            type: '',
            resultsPerPage: 1000,
            stream: that.data.id
          },
          success: (res) => {
            var h = res.data.data.items
            if (h.length > 0) {
              var myArr = []
              var c = 0
              h.forEach(i => {
                c++
                i.id = c
                if (i.type == 'question' || i.type == 'answer') {
                  i.content = JSON.parse(i.content)
                }
                myArr.push(i)
              })
              var j = h.length - 1
              var idx = h[j].id
              // console.log(h, idx)
              that.setData({
                tellData: h,
                idx: idx,
              })
            }
          }
        })
      },
      //与socket建立连接
      connectStart: function () {
        var that = this
          ws = wx.connectSocket({
            url: myurl,
            header: {
              "Authorization": app.globalData.token,
              'content-type': 'application/json'
            },
            data: JSON.stringify({
              token: app.globalData.token,
              type: 3,
              payLoad: {
                topic: that.data.fjh
              }
            }),
            success: (res) => {
              // console.log("进入聊天", res)
            },
            fail: (err) => {
              wx.showToast({
                title: '网络异常!',
              })
              console.log(err)
            },
          })
        //  连接成功
        wx.onSocketOpen((res) => {
          console.log('WebSocket 成功连接', res)
          that.resMes()
          //  开始心跳
          that.startHeartBeat()
        })
        //连接失败
        wx.onSocketError((err) => {
          console.log('websocket连接失败', err);
          twice=0
          that.connectStart()
        })
      },
      // 开始心跳
      startHeartBeat: function () {
        // console.log('socket开始心跳')
        var that = this;
        heart = 'heart';
        that.heartBeat();
      },
      // 心跳检测
      heartBeat: function () {
        var that = this;
        if (!heart) {
          return;
        }
        var xtData = {
          token: app.globalData.token,
          type: 1,
          payLoad: ""
        }
        // console.log(JSON.stringify({ xtData }))
        that.sendSocketMessage({
          msg: JSON.stringify(xtData),
          data: JSON.stringify(xtData),
          success: function (res) {
            // console.log('socket心跳成功',res);
            if (heart) {
              heartBeatTimeOut = setTimeout(() => {
                that.heartBeat();
              }, 5000);
            }
          },
          fail: function (res) {
            console.log('socket心跳失败');
            if (heartBeatFailCount > 2) {
              // 重连
              console.log('socket心跳失败')
              that.connectStart();
            }
            if (heart) {
              heartBeatTimeOut = setTimeout(() => {
                that.heartBeat();
              }, 5000);
            }
            heartBeatFailCount++;
          },
        });
      },
      // 进入聊天
      resMes: function () {
        var that = this
        var joinData = {
          token: app.globalData.token,
          type: 3,
          payLoad: JSON.stringify({
            topic: that.data.fjh
          }),
        }
        // console.log(joinData)
        that.sendSocketMessage({
          msg: JSON.stringify(joinData),
          data: JSON.stringify(joinData),
          success: function (res) {
            // console.log('进入房间成功', res);
            that.deal()
          },
          fail: function (err) {
            console.log('进入房间失败');
          },
        })
      },
      // 结束心跳
      stopHeartBeat: function () {
        // console.log('socket结束心跳')
        var that = this;
        heart = '';
        if (heartBeatTimeOut) {
          clearTimeout(heartBeatTimeOut);
          heartBeatTimeOut = null;
        }
        if (connectSocketTimeOut) {
          clearTimeout(connectSocketTimeOut);
          connectSocketTimeOut = null;
        }
      },
      // 消息发送
      foo: function () {
        if (this.data.inputValue) {
          //Do Something
        } else {
          //Catch Error
        }
        this.setData({
          inputValue: ''//将data的inputValue清空
        });
        return;
      },
      sayValue: function (e) {
        var that = this
        // console.log(this.data.isSend)
        if (that.data.isSend == 'ask') {
          that.setData({
            isSend: 'send'
          })
        }
        that.setData({
          sayValue: e.detail.value
        })
      },
      sendMes: function (e) {
        var that = this
        // console.log(this.data.sayValue, 111)
        var myInput = this.data.sayValue
        var token = app.globalData.token
        if (that.data.isSend == 'sureAsk') {
          wx.request({
            url: server + 'api/question/add',
            method: 'POST',
            header: {
              "Authorization": app.globalData.token,
              'content-type': 'application/json'
            },
            data: {
              content: myInput,
              streamId: that.data.id
            },
            success: (res) => {
              console.log(res, '我的提问')
            }
          })
        } else {
          // console.log(app.globalData.userInfo)
          var chatInfo = {
            user: app.globalData.userInfo.id,
            displayName: app.globalData.userInfo.displayName,
            avatarurl: app.globalData.userInfo.avatarUrl,
            stream: that.data.id,
            content: myInput,
            type: "message",
            createdat: "2018-10-8 14:30"
          }
          var sendData = {
            token: token,
            type: 2,
            payLoad: JSON.stringify({
              topic: that.data.fjh,
              chatInfo: JSON.stringify(chatInfo)
            })
          }
          // console.log(JSON.stringify(sendData))
          that.sendSocketMessage({
            msg: JSON.stringify(sendData)
          })
        }
        that.setData({
          sayValue: '',
          isSend: 'ask'
        })
      },
      // 通过 WebSocket 连接发送数据
      sendSocketMessage: function (options) {
        var that = this
        if (socketOpen) {
          wx.sendSocketMessage({
            data: options.msg,
            success: function (res) {
              if (options) {
                options.success && options.success(res);
              }
            },
            fail: function (res) {
              if (options) {
                options.fail && options.fail(res);
              }
            }
          })
        } else {
          socketMsgQueue.push(options.msg)
        }
        // ws.closeSocket();
        // that.deal()
      },
      //  监听socket
      deal: function () {
        var that = this
        ws.onOpen(res => {
          socketOpen = true;
          console.log('监听 WebSocket 连接打开事件。', res)
        })
        ws.onClose(onClose => {
          console.log('监听 WebSocket 连接关闭事件。', onClose)
          // socketOpen = false;
          // that.connectStart()
        })
        ws.onError(onError => {
          console.log('监听 WebSocket 错误。错误信息', onError)
          socketOpen = false
        })
        ws.onMessage(onMessage => {
          var res = JSON.parse(onMessage.data)
          // console.log(res,"接收到了消息")
          if (res.code == 200) {
            // console.log('服务器返回的消息', res.data)
            var resData = JSON.parse(res.data)
            var arr = that.data.tellData
            resData.id = arr.length + 1
            if (resData.type == 'question' || resData.type == 'answer') {
              resData.content = JSON.parse(resData.content)
              console.log('这是提问', resData.type, resData.content.content)
            }
            arr.push(resData)
            console.log(resData, arr.length)
            that.setData({
              tellData: arr,
              idx: resData.id
            })
          } else {
          }
        })
      },
      time: function (a) {
        var data = new Date(a)
        var year = data.getFullYear();
        var month = data.getMonth() + 1;
        var day1 = data.getDate();
        var hh = data.getHours(); //截取小时
        var mm = data.getMinutes(); //截取分钟
        if (month < 10) {
          month = '0' + month
        }
        if (day1 < 10) {
          day1 = '0' + day1
        }
        if (hh < 10) {
          hh = '0' + hh
        }
        if (mm < 10) {
          mm = '0' + mm
        }
        var newday = month + "月" + day1 + ' ' + hh + ':' + mm
        return newday
      },
      inputing: function () {
        console.log('获取焦点')
        this.setData({
          isSend: 'send'
        })
      },
      inputed: function () {
        // console.log('失去焦点')
        this.setData({
          isSend: 'ask',
        })
      },
      ask: function () {
        // console.log('提问')
        this.setData({
          myinputing: true,
          isSend: 'sureAsk'
        })
      },
    })

以上仅是前端部分本人小程序websocket的使用实例,具体的情况需要配合自己的服务端。希望对大家有所帮助,也欢迎大家互相讨论。

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论