微信小程序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 相关文章推荐
索趣科技的答案
Feb 07 Javascript
学习从实践开始之jQuery插件开发 对话框插件开发
Apr 26 Javascript
浅析JS刷新框架中的其他页面 &amp;&amp; JS刷新窗口方法汇总
Jul 08 Javascript
jquery ajax应用中iframe自适应高度问题解决方法
Apr 12 Javascript
基于jQuery实现咖啡订单管理简单应用
Feb 10 Javascript
如何写好你的JavaScript【推荐】
Mar 02 Javascript
jQuery实现动态删除LI的方法
May 30 jQuery
element-ui upload组件多文件上传的示例代码
Oct 17 Javascript
vue-cli3 项目从搭建优化到docker部署的方法
Jan 28 Javascript
少女风vue组件库的制作全过程
May 15 Javascript
vue路由切换之淡入淡出的简单实现
Oct 31 Javascript
深入详解JS函数的柯里化
Jun 09 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
Email+URL的判断和自动转换函数
2006/10/09 PHP
PHP4实际应用经验篇(3)
2006/10/09 PHP
PHP 实现多服务器共享 SESSION 数据
2009/08/15 PHP
PHP安全配置详细说明
2011/09/26 PHP
php切割页面div内容的实现代码分享
2012/07/31 PHP
php 中文字符串首字母的获取函数分享
2013/11/04 PHP
php根据生日计算年龄的方法
2015/07/13 PHP
php使用CURL模拟GET与POST向微信接口提交及获取数据的方法
2016/09/23 PHP
php 与 nginx 的处理方式及nginx与php-fpm通信的两种方式
2018/09/28 PHP
php实现QQ小程序发送模板消息功能
2019/09/18 PHP
PHP常见的序列化与反序列化操作实例分析
2019/10/28 PHP
jquery下操作HTML控件的实现代码
2010/01/12 Javascript
javascript 45种缓动效果 非常酷
2011/06/28 Javascript
html组件不可输入(只读)同时任何组件都有效
2013/04/01 Javascript
jquery 自定义容器下雨效果可将下雨图标改为其他
2014/04/23 Javascript
jquery.gridrotator实现响应式图片展示画廊效果
2015/06/23 Javascript
探讨JavaScript语句的执行过程
2016/01/28 Javascript
基于javascript实现按圆形排列DIV元素(二)
2016/12/02 Javascript
微信小程序 动态绑定数据及动态事件处理
2017/03/14 Javascript
微信小程序使用radio显示单选项功能【附源码下载】
2017/12/11 Javascript
基于Proxy的小程序状态管理实现
2019/06/14 Javascript
JS实现4位随机验证码
2020/10/19 Javascript
[40:03]RNG vs VG 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
Python设计模式之代理模式实例
2014/04/26 Python
Python中getattr函数和hasattr函数作用详解
2016/06/14 Python
PyQt5主窗口动态加载Widget实例代码
2018/02/07 Python
Python实现病毒仿真器的方法示例(附demo)
2020/02/19 Python
解决keras backend 越跑越慢问题
2020/06/18 Python
Weekendesk意大利:探索多种引人入胜的周末主题
2016/10/14 全球购物
对于没有初始化的变量的初始值可以作怎样的假定
2014/10/12 面试题
零件设计自荐信范文
2013/11/27 职场文书
普通员工辞职信
2014/01/17 职场文书
省优秀教师事迹材料
2014/01/30 职场文书
那些美到让人窒息的诗句,值得你收藏!
2019/08/20 职场文书
浅谈Nginx 中的两种限流方式
2021/03/31 Servers
Windows Server 2012 R2 磁盘分区教程
2022/04/29 Servers