微信小程序websocket實現(xiàn)即時聊天功能
今天給大家分享一下本人做小程序使用websocket的一點小經(jīng)驗,希望對大家有所幫助。
使用之前肯定首先要了解一下websocket是什么,簡單來講websocket就是客戶端與服務(wù)器之間專門建立的一條特殊通道,請求只需要請求一次,而且還可以從通道實時獲取服務(wù)器數(shù)據(jù),非常適合應(yīng)用到實時應(yīng)用上。
因為這里本人是分享小程序,所以就不去深究websocket的底層和協(xié)議了,感興趣的朋友可以去看下websocket協(xié)議
建議大家在做之前先看看微信小程序官方提供的api關(guān)于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}}回復(fù){{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'>發(fā)送</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//這是自己的服務(wù)端接口地址設(shè)置于app.js
var WxParse = require('../../wxParse/wxParse.js');
var tellPage = 1
var myurl='ws://+"你自己的鏈接地址"'
var ws // socket發(fā)送的消息隊列
var socketMsgQueue = []
var socketOpen = true // 判斷心跳變量
var heart = '' // 心跳失敗次數(shù)
var heartBeatFailCount = 0 // 終止心跳
var heartBeatTimeOut = null; // 終止重新連接
var connectSocketTimeOut = null;
Page({
/**
* 頁面的初始數(shù)據(jù)
*/
data: {
sayValue:'',
tellData:[],//聊天消息
idx:'',
id:'',
fjh:'',//房間號
myinputing:'',
isSend: 'ask',
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面加載
*/
onLoad: function (options) {
this.setData({
id: options.id,
fjh:options.roomNum,
})
this.history(1)
this.connectStart()
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面初次渲染完成
*/
onReady: function () {
//監(jiān)聽websocket連接狀態(tài)
this.deal()
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面顯示
*/
onShow: function () {
console.log()
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面隱藏
*/
onHide: function () {
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面卸載
*/
onUnload: function () {
var that = this
//離開頁面銷毀websocket并恢復(fù)初始數(shù)據(jù)
wx.closeSocket()
twice = 0
socketOpen = true
heart = '' // 心跳失敗次數(shù)
heartBeatFailCount = 0 // 終止心跳
heartBeatTimeOut = null; // 終止重新連接
connectSocketTimeOut = null;
},
/**
* 頁面相關(guān)事件處理函數(shù)--監(jiān)聽用戶下拉動作
*/
onPullDownRefresh: function () {
},
/**
* 頁面上拉觸底事件的處理函數(shù)
*/
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: '網(wǎng)絡(luò)異常!',
})
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('進入房間失敗');
},
})
},
// 結(jié)束心跳
stopHeartBeat: function () {
// console.log('socket結(jié)束心跳')
var that = this;
heart = '';
if (heartBeatTimeOut) {
clearTimeout(heartBeatTimeOut);
heartBeatTimeOut = null;
}
if (connectSocketTimeOut) {
clearTimeout(connectSocketTimeOut);
connectSocketTimeOut = null;
}
},
// 消息發(fā)送
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 連接發(fā)送數(shù)據(jù)
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()
},
// 監(jiān)聽socket
deal: function () {
var that = this
ws.onOpen(res => {
socketOpen = true;
console.log('監(jiān)聽 WebSocket 連接打開事件。', res)
})
ws.onClose(onClose => {
console.log('監(jiān)聽 WebSocket 連接關(guān)閉事件。', onClose)
// socketOpen = false;
// that.connectStart()
})
ws.onError(onError => {
console.log('監(jiān)聽 WebSocket 錯誤。錯誤信息', onError)
socketOpen = false
})
ws.onMessage(onMessage => {
var res = JSON.parse(onMessage.data)
// console.log(res,"接收到了消息")
if (res.code == 200) {
// console.log('服務(wù)器返回的消息', 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的使用實例,具體的情況需要配合自己的服務(wù)端。希望對大家有所幫助,也歡迎大家互相討論。
相關(guān)文章
JavaScript 節(jié)點操作 以及DOMDocument屬性和方法
最近發(fā)現(xiàn)DOMDocument對象很重要,還有XMLHTTP也很重要 注意大小寫一定不能弄錯.2007-12-12
JS實現(xiàn)十字坐標(biāo)跟隨鼠標(biāo)效果
這篇文章給大家分享一下通過JS實現(xiàn)十字坐標(biāo)跟隨鼠標(biāo)效果的代碼,有需要的朋友參考學(xué)習(xí)下吧。2017-12-12
JavaScript中函數(shù)的防抖與節(jié)流詳解
這篇文章主要為大家詳細(xì)介紹了JavaScript中函數(shù)的防抖與節(jié)流,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-02-02
JavaScript高級程序設(shè)計 讀書筆記之九 本地對象Array
本地對象Array,數(shù)組等操作函數(shù)2012-02-02

