微信小程序websocket实现即时聊天功能
程序员文章站
2022-07-20 11:23:38
今天给大家分享一下本人做小程序使用websocket的一点小经验,希望对大家有所帮助。
使用之前肯定首先要了解一下websocket是什么,简单来讲websocket就是...
今天给大家分享一下本人做小程序使用websocket的一点小经验,希望对大家有所帮助。
使用之前肯定首先要了解一下websocket是什么,简单来讲websocket就是客户端与服务器之间专门建立的一条特殊通道,请求只需要请求一次,而且还可以从通道实时获取服务器数据,非常适合应用到实时应用上。
因为这里本人是分享小程序,所以就不去深究websocket的底层和协议了,感兴趣的朋友可以去看下websocket协议
建议大家在做之前先看看微信小程序官方提供的api关于,因为微信的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的使用实例,具体的情况需要配合自己的服务端。希望对大家有所帮助,也欢迎大家互相讨论。