微信小程序WebScoket的应用

前言

荔园土木人这个项目接近尾声了,终于是有时间写一篇关于WebSocket的博客了。之前我把聊天的界面给搭建出来了,但是还没有完成真正的一个聊天系统,那么现在,就是完善的时候了。

wx.connectSocket(OBJECT)

创建一个 WebSocket连。接很简单,就三行代码。这个是后端给我的Socket地址,小程序记得将这个地址列为合法域名

1
2
3
wx.connectSocket({
url: 'wss://socket.szucceaa.com/?fid=' + wx.getStorageSync('userInfo').id + '&tid=' + e.id
})

wx.onSocketOpen(CALLBACK)

监听WebSocket连接打开事件,因为socket是一个长连接,要在onSocketOpen事件里面才能一直接收服务器发送过来的广播。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
wx.onSocketOpen(function (res) {
that.setData({
socketOpen: true
})

console.log('WebSocket连接已打开!')

// 接收消息
wx.onSocketMessage(function (res) {
var obj = {};
obj.receive = false;
obj.content = res.data;
that.data.chatData.push(obj);
that.setData({
chatData: that.data.chatData
})
})

wx.onSocketClose(function (res) {
console.log('WebSocket连接已关闭!');
that.connectSocket(e);
})
})

我的聊天的内容是一个数组对象chatData,然后对方给我发消息的话,chatData.receive是为false,从而判断是我发出去的还是对方给我发的。

因此接收消息的时候我建立了一个新数组obj,然后将服务器广播的内容和receive push到原数组chatData里面,双向绑定从而将数组在页面中渲染出来。

wx.onSocketMessage(CALLBACK)

监听WebSocket接受到服务器的消息事件。这里呢其实在上面的代码已经展示了,onSocketMessage函数

1
2
3
4
5
6
7
8
9
10
11
// 接收消息
wx.onSocketMessage(function (res) {
var obj = {};
obj.receive = false;
obj.content = res.data;
that.data.chatData.push(obj);
that.setData({
chatData: that.data.chatData
})
that.sendMessage();
})

wx.sendSocketMessage(OBJECT)

通过 WebSocket 连接发送数据,需要先 wx.connectSocket,并在 wx.onSocketOpen 回调之后才能发送。

这里我写了一个函数sendSocketMessage,在发送消息(bindconfirm事件)中调用,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// [发送消息]
sendSocketMessage: function (msg) {
var that = this;
if (that.data.socketOpen) {
wx.sendSocketMessage({
data: msg
})
that.setData({
chatData: that.data.chatData
})
} else {
console.log('发送失败');
wx.showToast({
title: '发送失败',
icon: 'none',
duration: 1200
})
}
},

也非常的简单,先判断socket是否已经连接,然后sendSocketMessage发送一条data。

关键代码

1
2
3
wx.sendSocketMessage({
data: msg
})

wx.closeSocket(OBJECT)

关闭 WebSocket 连接。我在页面卸载的时候调用了这个api,当页面关闭时,关闭socket连接

1
2
3
4
5
6
7
onUnload() {
wx.closeSocket();

wx.onSocketClose(function (res) {
console.log('WebSocket连接已关闭!');
})
},

wx.onSocketClose(CALLBACK)

监听WebSocket关闭,我有两个地方调用这个api,因为后台的socket时效性是一分钟,那么一分钟过去了就要重启打开socket。所以第一个地方是在connectSocket这个方法里面,当监听到socket连接断开的时候,重新执行connectSocket这个方法,这样一个轮询可保证socket不会中途断开。

第二个地方就是页面卸载的时候了,判断socket是否关闭成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// [打开socket]
connectSocket: function (e) {
var that = this;
if (wx.getStorageSync('userInfo').id == e.id) {
console.log('不能与自己聊天');
return false
}
wx.connectSocket({
url: 'wss://socket.szucceaa.com/?fid=' + wx.getStorageSync('userInfo').id + '&tid=' + e.id
})

wx.onSocketOpen(function (res) {
that.setData({
socketOpen: true
})

console.log('WebSocket连接已打开!')

// 接收消息
wx.onSocketMessage(function (res) {
var obj = {};
obj.receive = false;
obj.content = res.data;
that.data.chatData.push(obj);
that.setData({
chatData: that.data.chatData
})
that.sendMessage();
})

wx.onSocketClose(function (res) {
console.log('WebSocket连接已关闭!');
that.connectSocket(e);
})
})
},

这样子就完成了一个聊天系统的开发,上一个效果图。

image

…等等,再做一个聊天列表就完善了吧。

聊天列表

由于聊天列表那块并没有建立socket,只是普通的request请求。那为了接收信息即时性,这里我做了一个轮询,当请求成功时过两秒钟再次请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// [获取列表数据]
getChatData() {
var that = this;
var token = 'bearer' + ' ' + wx.getStorageSync('userToken').access_token;
var data = {
page: that.data.page,
per_page: that.data.paginal
}
var header = {
Accept: 'application/json',
Authorization: token
}
utils.httpGet('api/users/own/conversations', data, header, function (res) {
if (res.status == 200) {
that.setData({
ChatArr: that.data.ChatArr
})
}
})
},

但是这里遇到了一个问题,请求到的数组全部渲染到页面上去吗?这个样子页面性能消耗挺大的吧。因此我这里做了一个操作,比较两个数组,将不同的值ubshift到最上边

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
if (res.status == 200) {
if (that.data.ChatArr.length == 0) {
that.data.ChatArr = res.data.data
that.setData({
ChatArr: that.data.ChatArr
})
} else {
var result = [];
for (var i = 0; i < res.data.data.length; i++) {
var obj1 = res.data.data[i];
var num1 = obj1.news;
var isExist = false;
for (var j = 0; j < that.data.ChatArr.length; j++) {
var obj2 = that.data.ChatArr[j];
var num2 = obj2.news;
if (num2 == num1&&obj1.unread == obj2.unread) {
isExist = true;
break;
}
}
if (!isExist) {
result.push(obj1);
}
}
if (result.length) {
for (var i = 0; i < that.data.ChatArr.length; i++) {
if (that.data.ChatArr[i].id == result[0].id) {
that.data.ChatArr.splice(i, 1);
break;
}
}
that.data.ChatArr.unshift(result[0]);
that.setData({
ChatArr: that.data.ChatArr
})
console.log(that.data.ChatArr);
}
}


that.data.timeout = setTimeout(() => {
that.getChatData();
that.setData({
// ChatArr: []
})
}, 2000);
}

有点长,反正逻辑就上边说的这样,慢慢看吧hhh,今天就到这了,放个图看看

image