欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

微信小程序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的使用实例,具体的情况需要配合自己的服务端。希望对大家有所帮助,也欢迎大家互相讨论。