微信小程序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 相关文章推荐
form中限制文本字节数js代码
Jun 10 Javascript
ExtJS的FieldSet的column列布局
Nov 20 Javascript
event.X和event.clientX的区别分析
Oct 06 Javascript
JavaScript 事件入门知识
Apr 13 Javascript
JavaScript获取并更改input标签name属性的方法
Jul 02 Javascript
jquery实现无刷新验证码的简单实例
May 19 Javascript
Backbone中View之间传值的学习心得
Aug 09 Javascript
详解支持Angular 2的表格控件
Jan 19 Javascript
vue.js从安装到搭建过程详解
Mar 17 Javascript
详解Vuex管理登录状态
Nov 13 Javascript
Vuex中实现数据状态查询与更改
Nov 08 Javascript
Vue实现购物车实例代码两则
May 30 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
Dedecms常用函数解析
2008/02/01 PHP
codeigniter集成ucenter1.6双向通信的解决办法
2014/06/12 PHP
php获取指定(访客)IP所有信息(地址、邮政编码、国家、经纬度等)的方法
2015/07/06 PHP
php 数组字符串搜索array_search技巧
2016/07/05 PHP
php获取服务器操作系统相关信息的方法
2016/10/08 PHP
php通过header发送自定义数据方法
2018/01/18 PHP
js页面跳转常用的几种方式
2010/11/25 Javascript
jQuery$命名冲突怎么办如何解决
2014/01/16 Javascript
JQuery调用绑定click事件的3种写法
2015/03/28 Javascript
Javascript之面向对象--封装
2016/12/02 Javascript
js 中rewrap-ajax.js插件实例代码
2017/10/20 Javascript
vue自定义全局组件(自定义插件)的用法
2018/01/30 Javascript
vue-baidu-map 进入页面自动定位的解决方案(推荐)
2018/04/28 Javascript
vue-cli中使用高德地图的方法示例
2019/03/28 Javascript
vue 图片裁剪上传组件的实现
2020/11/12 Javascript
JavaScript this关键字的深入详解
2021/01/14 Javascript
python的id()函数介绍
2013/02/10 Python
Python3实现Web网页图片下载
2016/01/28 Python
详解Python实现多进程异步事件驱动引擎
2017/08/25 Python
用Python删除本地目录下某一时间点之前创建的所有文件的实例
2017/12/14 Python
Python 3.x 判断 dict 是否包含某键值的实例讲解
2018/07/06 Python
快速了解Python开发环境Spyder
2020/06/29 Python
HTML5中使用json对象的实例代码
2018/09/10 HTML / CSS
什么是会话Bean
2015/05/14 面试题
专科应届生求职信
2013/11/24 职场文书
毕业生自荐信如何写
2014/03/24 职场文书
商业企业管理专业求职信
2014/07/10 职场文书
查摆问题自查报告范文
2014/10/13 职场文书
2014年扫黄打非工作总结
2014/12/03 职场文书
施工安全员岗位职责
2015/04/11 职场文书
高中运动会前导词
2015/07/20 职场文书
追悼会家属答谢词
2015/09/29 职场文书
企业愿景口号
2015/12/25 职场文书
《田忌赛马》教学反思
2016/02/19 职场文书
CSS 圆形进度栏
2021/04/06 HTML / CSS
PHP 时间处理类Carbon
2022/05/20 PHP