读万卷书不如行万里路,行万里路不如阅人无数,阅人无数不如名师指路。站着巨人身上,你可以看的更高、更远。

一、webSocket 初始化

initWebSocket 方法中,初始化 webSocket。

this.socket = new Socket('ws://192.168.11.198:12000/msg', {userId: '1234',token: 'token-demo',sysCode: '001',
})

在文件中,引入 socket.js 文件(webSocket 的基本配置)。

export default class {constructor (url, opts = {}) {...this.init(url, opts)}
}

调用 init 初始化方法,连接 websocket,同时绑定系统事件。

init (url, opts) {this.client = new WebSocket(url).....return this.client
}

webSocket 相关事件

this.client.onopen = () => {}  // 连接建立时触发
this.client.onmessage = (event) => {} // 客户端接收服务端数据时触发
this.client.onerror = () => {}  // 通信发生错误时触发
this.client.onclose = () => {}  // 连接关闭时触发

二、客户端与服务端建立连接

在建立连接时,调用 login 方法。

this.client.onopen = () => {this.login(opts.userId, opts.sysCode, opts.token)
}

在登陆方法中,调用 send 方法。

login (userId, sysCode, token) {const operation = 'Auth'......this.send(operation, data, token)
}

在 send 方法中, 首先检查 websocket 的连接状态。

this.client.readyState 为 1 时,表示 webSocket 已经连接成功,可以通讯。调用 this.client.send 方法发送信息。

/*** 发送事件* @param {string} operation 事件类型* @param {object} data 事件参数
*/
send (operation, data) {const readyState = this.client.readyStatereturn new Promise((resolve, reject) => {if (this.client.readyState === 1) {const message = {operation,data,token: this.token,}this.client.send(JSON.stringify(message))resolve()} else {reject(new Error(`当前连接状态为:${readyState}, 无法发送消息`))}})
}

接收来自服务端的消息。

this.client.onmessage = (event) => {const resp = JSON.parse(event.data)......this.events[resp.operation](resp) // event 上绑定触发类型和结果。
}

在业务逻辑中,对绑定的登录事件进行回调。在登录成功后,回调服务器推送过来的消息,同时将 result 中返回的 token,传入调用心跳方法中。

this.socket.on('Auth', (result) => {console.log('Auth 回调', result)......// 启动心跳this.socket.heartStart(this.token)
})

on 绑定自定义事件。

on (operation, func) {this.events[operation] = func
}

三、启动心跳(定时器)

采用定时器,在一定的时间间隔内,给服务端发送一次消息,说明客户端连接到服务端的。

heartStart (token) {this.heartTimer = window.setInterval(() => {this.heartBeat(token)}, this.heartInterval)this.heartBeat(token)......
}

在心跳方法中,调用 send 方法。

heartBeat (token) {const operation = 'HeartBeat'...this.send(operation, data, token)
}

同时在 heartStart 方法中,绑定回调事件。

heartStart (token) {......this.on('HeartBeat', () => {console.log('接送到心跳回应')})
}

接收来自服务端的消息。

this.client.onmessage = (event) => {const resp = JSON.parse(event.data)......this.events[resp.operation](resp) // event 上绑定触发类型和结果。
}

最后绑定的 HeartBeat 事件回调中,打印信息:接送到心跳回应。

四、下拉获取分页数据

如何在滚动列表时,添加触底事件,向服务端发送获取该类型列表的下一页数据呢。

在触底事件中,只需添加下面代码:

this.socket.msgPull(this.token, type, row.id)

在消息分页 msgPull 方法中,调用 send 方法。

msgPull (token, type, pageId, size) {const operation = 'Pull'......this.send(operation, data, token)
}

send 发送事件中,使用 this.client.send(JSON.stringify(message)) 发送信息给服务器。

在 this.client.onmessage 中接收服务端返回到客户端的信息。

this.client.onmessage = (event) {const resp = JSON.parse(event.data)......this.events[resp.operation](resp)
}

在 Pull 回调中,获取从服务端回调过来的信息。

this.socket.on('Pull', (result) => {console.log('Pull 回调', result)
})

敲敲黑板,重点来了。

1、如何监听列表滚动到底部时,调用 Pull 类型的 send 方法获取下一页数据;

2、如何区分当前滚动列表需要加载下一页的数据类型;

3、若该类型列表无更多数据,触底事件频繁调用获取下一页数据,如何优化呢?

调用 handleInfiniteOnLoad 方法时,会传入列表的类型,我们会将需要加载下一页数据的类型传给服务端的;在 Pull 操作类型的回调中,我们将返回的结果进行判断。

this.socket.on('Pull', (result) => {this.loading = false// end: '1' => 结束,没有下一页, '0' => 有下一页if (result.data.end === '0') {switch (result.data.type) {case 'INFORM':this.msgTable.informs = [...this.msgTable.informs, ...result.data.messages]break......}} else {// 没有下一页时移除滚动事件if (!this.noMoreFlagList.includes(result.data.type)) {this.noMoreFlagList.push(result.data.type)}}
})

noMoreFlagList 为没有下一页的列表类型;该类型列表无更多数据,禁止提交 pull 操作类型的事件。

handleInfiniteOnLoad (type) {let rowif (type === 'INFORM') {row = this.msgTable.informs[this.msgTable.informs.length - 1]} ......// 匹配标识是否已没有下一页if (!this.noMoreFlagList.includes(type)) {this.loading = truethis.socket.msgPull(this.token, type, row.id)}
},

五、后端主动推送消息

当后端主动推送消息时,我们又应该如何接收呢?

在服务端推送消息给客户端时,会获取消息的类型和数据,对应的在消息回调中可以获取相应的数据。

initWebSocket () {......// 后端主动推送消息this.socket.on('Push', (result) => {console.log('push', result)this.$message.info({message: '您好',description: '您有新的未读消息,请注意查收',})switch (result.data.type) {case 'INFORM':this.msgTable.informs.unshift(result.data)break......}// 未读总数+1this.totalUnreadCount++})
},

六、已读消息处理

首先用户点击浏览器,调用 handleRead 事件。

handleRead (msgId, status) {// 已读消息则不再发起阅读if (status === '0' && !this.readedList.includes(msgId)) {this.socket.msgRead(this.token, msgId)}
},

在 msgRead 方法中,调用【已读】类型的 send 方法。

msgRead (token, msgId) {const operation = 'Read'......this.send(operation, data, token)
}

在业务逻辑中,对已读进行回调,将返回的结果 id 放入 readedList 已读列表中,同时对未读数量 totalUnreadCount 进行 -1 操作。

this.socket.on('Read', (result) => {this.readedList.push(result.data.msgId)// 未读总数-1this.totalUnreadCount--
})

页面展示已读与未读

// item.vue 组件
<divclass="z-msg__item":class="{'z-msg__item--read': (itemData.status === '1' || judgeReaded(itemData.id))}"@click="itemClick(itemData)"
>......
</div>

status 为 1 或者 readedList 数组中存在点击过的消息 Id时,则为已读状态;

// 处理已读
judgeReaded (msgId) {if (this.readedList.includes(msgId)) {return true} else {return false}
},
z-msg__item--read {opacity: 0.6;
}

注意:首先通过 userId 和 token 与用户相关的字段,与服务端建立连接(用于身份标识,这里的 userId 和 token 是登录系统后的用户信息)。在建立连接之后的回调中,返回的 result 里面有个 token 字段。这个由服务端返回的字段,在后续的 HeartBeat、Pull、Push、Read 类型的 send 方法中,作为客户端与服务端的传递消息的桥梁。

webSocket 实现消息推送、心跳、已读消息、加载更多等功能相关推荐

  1. mqtt消息推送 java_MQTT+ActiveMQ实现消息推送(服务器端java实现)

    上一篇文章已经介绍了mqtt+activemq实现消息推送移动端的实现,也介绍了利用自带的web console进行消息发布的方法.但是在具体的项目应用中,当我们将需要将该消息推送模块嵌入到一个后台管 ...

  2. 国内APP消息推送机制以及微信消息延迟问题剖析

    转自:https://club.huawei.com/thread-15878044-1-1.html 一.前言 随着安卓手机以及QQ/微信/支付宝/滴滴出行/美图外卖等一大批移动通信/移动消费应用的 ...

  3. app消息推送服务器端,系统服务:APP消息推送服务

    APP消息推送服务开通方法 在云表官网-管理控制台中,选择要开通APP消息推送服务的服务器,然后选择要开通APP消息推送服务的应用空间,点击对应应用空间的"应用空间管理". 在进入 ...

  4. 企业微信H5_消息推送概述,发送应用消息示例

    文章目录 一.阅读和调试 1. 文档阅读 2. postman发送消息 二.实战演练 2.1. 发送消息 2.2. 前端代码 2.3. 后端代码 2.4. 发送文本消息 2.5. 接收消息 三.源码分 ...

  5. python消息推送_Python阿里云消息推送调用API

    很多公司测试APP推送时候,应该也是很头疼:推送环境:测试.正式,稍不注意就把测试的push到正式上,导致所有用户都收到 例子很多: 其实阿里.极光都有推送Api,直接调用API就ok,特别是有的公司 ...

  6. 微信公众号消息推送开发(模板消息):准备工作[公众平台环境配置](一)

     专栏简介

  7. 企业微信消息推送和钉钉消息推送python代码封装

    前言:目前很多公司用的是企业微信或者钉钉,对于服务的可用性都会有一个告警通知,方面我们及时了解信息,这里我做了一个简单的封装,方便大家使用! #!/usr/bin/env python # _*_ c ...

  8. 消息推送技术干货:美团实时消息推送服务的技术演进之路

    本文由美团技术团队分享,作者"健午.佳猛.陆凯.冯江",原题"美团终端消息投递服务Pike的演进之路",有修订. 1.引言 传统意义上来说,实时消息推送通常都是 ...

  9. Web 实时消息推送详解

    title: Web 实时消息推送详解 category: 系统设计 head: meta name: keywords content: 消息推送,短轮询,长轮询,SSE,Websocket,MQT ...

最新文章

  1. List and ArrayList
  2. 晶体三极管如何工作的?不,我是问它的真实工作原理
  3. puppet 类、模块
  4. Kotlin问题解决
  5. TCP第四次挥手为什么要等待2MSL(最长报文段寿命,Maximum Segment Lifetime)
  6. CSS 设计模式一 元素
  7. java asynchronize_Java 中synchronize函数的实例详解
  8. 6年Python开发,教你一天入门 Python
  9. Linux 中设置环境变量的三种方法
  10. python学习笔记2018-9-18
  11. maven如何直接手动下载jar包
  12. AI辅助构建知识图谱:关系抽取
  13. 微服务笔记(二) 服务发现
  14. Linux查看文件内容的6种命令
  15. android 音乐均衡器,App+1 | 不懂均衡器调校也能量身定制,无需折腾的 Android 音效提升工具...
  16. java技术可行性分析_java毕业设计管理系统需求分析
  17. 基于java语言的C/S模式网络聊天室软件
  18. 基于matlab的基带gmsk调制解调,基于MATLAB的GMSK调制解调实验
  19. 中小企业生产信息化:私有系统还是云方案?
  20. CodeForces 592B

热门文章

  1. Feedback Prize-Kaggle比赛调研
  2. 火星人学习第一周——虚幻引擎基础应用笔记
  3. Solidity Gas消耗
  4. 希望传说手游如何在电脑上玩 希望传说手游模拟器教程
  5. 使用电源管理模块有效控制GaN功率放大器的电源开关
  6. 2014年英语专升本英语阅读「Part II 阅读专区」【文章(图片)、答案、词汇记忆】
  7. N行M列每个位置放Aij个1厘米的正方体,求表面积
  8. P2P行业大数据征信前瞻
  9. React实现动画效果
  10. 关于云计算必知的关键核心技术