微信小程序websocket实现即时聊天功能


Posted in Javascript onMay 21, 2019

今天给大家分享一下本人做小程序使用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的使用实例,具体的情况需要配合自己的服务端。希望对大家有所帮助,也欢迎大家互相讨论。

Javascript 相关文章推荐
JavaScript 全角转半角部分
Oct 28 Javascript
TBCompressor js代码压缩
Jan 05 Javascript
真正好用的js验证上传文件大小的简单方法
Oct 27 Javascript
利用jQuery插件imgAreaSelect实现获得选择域的图像信息
Dec 02 Javascript
原生JavaScript实现AJAX、JSONP
Feb 07 Javascript
微信扫码支付零云插件版实例详解
Apr 26 Javascript
vue axios 在页面切换时中断请求方法 ajax
Mar 05 Javascript
vue获取当前激活路由的方法
Mar 17 Javascript
vue自定义指令实现方法详解
Feb 11 Javascript
vue 搭建后台系统模块化开发详解
May 01 Javascript
Typescript3.9 常用新特性一览(推荐)
May 14 Javascript
vue 获取url参数、get参数返回数组的操作
Nov 12 Javascript
Node.JS在命令行中检查Chrome浏览器是否安装并打开指定网址
May 21 #Javascript
taro开发微信小程序的实践
May 21 #Javascript
element-ui表格合并span-method的实现方法
May 21 #Javascript
详解关于表格合并span-method方法的补充(表格数据由后台动态返回)
May 21 #Javascript
浅谈React Native 传参的几种方式(小结)
May 21 #Javascript
JavaScript函数式编程(Functional Programming)声明式与命令式实例分析
May 21 #Javascript
JS判断数组里是否有重复元素的方法小结
May 21 #Javascript
You might like
虚拟主机中对PHP的特殊设置
2006/10/09 PHP
PHP文件读写操作之文件写入代码
2011/01/13 PHP
PHP中shuffle数组值随便排序函数用法
2014/11/21 PHP
php 截取GBK文档某个位置开始的n个字符方法
2017/03/08 PHP
Jquery ajaxsubmit上传图片实现代码
2010/11/04 Javascript
js模拟点击事件实现代码
2012/11/06 Javascript
JavaScript中for-in遍历方式示例介绍
2014/02/11 Javascript
js图片预加载示例
2014/04/30 Javascript
JavaScript 学习笔记之数据类型
2015/01/14 Javascript
js库Modernizr的介绍和使用
2015/05/07 Javascript
在JavaScript中用getMinutes()方法返回指定的分时刻
2015/06/10 Javascript
TableSort.js表格排序插件使用方法详解
2017/02/10 Javascript
javascript获取以及设置光标位置
2017/02/16 Javascript
React为 Vue 引入容器组件和展示组件的教程详解
2018/05/03 Javascript
JSON字符串操作移除空串更改key/value的介绍
2019/01/05 Javascript
Vue+element+cookie记住密码功能的简单实现方法
2020/09/20 Javascript
js 将多个对象合并成一个对象 assign方法的实现
2020/09/24 Javascript
原生js实现表格翻页和跳转
2020/09/29 Javascript
[56:13]DOTA2-DPC中国联赛定级赛 LBZS vs Phoenix BO3第一场 1月10日
2021/03/11 DOTA
python MultipartEncoder传输zip文件实例
2020/04/07 Python
基于python代码批量处理图片resize
2020/06/04 Python
python uuid生成唯一id或str的最简单案例
2021/01/13 Python
丝芙兰香港官网:Sephora香港
2018/03/13 全球购物
荷兰在线体育用品商店:Avantisport.nl
2018/07/04 全球购物
工作决心书范文
2014/03/11 职场文书
毕业寄语大全
2014/04/09 职场文书
高一学生期末评语
2014/04/25 职场文书
公司应聘自荐书
2014/06/14 职场文书
模具设计与制造专业自荐书
2014/07/01 职场文书
调研座谈会发言材料
2014/08/23 职场文书
干部对照检查材料范文
2014/08/26 职场文书
2014年法务工作总结
2014/12/11 职场文书
继承权公证书范本
2015/01/23 职场文书
大学生自荐书范文
2015/03/05 职场文书
爱心募捐通知范文
2015/04/27 职场文书
python实战之用emoji表情生成文字
2021/05/08 Python