背景
最近发现一款有意思的聊天产品discord,对此预研了类似的产品stream-chat及其social messaging demo的源码,根据其原理总结出一套设计思路
demo效果
设计思路
1.视图层
总的设计为左右结构,如图:
左模块:MessagingChannelListHeader用户信息、ChannelList频道列表
右模块:CreateChannel搜索用户区、ChannelInner频道具体内容(包括对话窗口和侧边栏)
2.数据层
数据层核心结构如图:
举个聊天室例子
按步骤拆解见下文
2.1第一步:建立双向通信连接(WebSocket协议)
由于聊天室需要实时同步每个用户窗口交互的效果,要求客户端和服务端能够双向通信,因此需要建立WebSocket连接。用于服务端主动向客户端发送数据。客户端可以使用ws建立连接。
不过,前端主动向后端发送数据的方式是采用https协议,https和WebSocket是兼容的。
2.2第二步:生成聊天室实例(client对象)
一个聊天室会生成一个client实例,client上有几个核心属性和方法如图:
client.on和client.off
on和off负责注册注销通用事件和聊天室事件,比如更新频道、删除频道、消息未读状态处理等。调用方式有两种(区别见client.dispatchEvent),如下:
第一种:client.on(handleEvent) 注册通用事件
第二种:client.on('xxx', handleEvent) 注册聊天室事件
client.listens
listens是一个事件集合,如图:
all:由 client.on(handleEvent) 注册,每调用一次就往all数组中添加一个事件元素。
聊天室事件:由client.on('xxx', handleEvent)注册,每调用一次就往聊天室事件数组中添加一个事件元素。比如,client.on('channel.update', handleEvent)调用n次,listens['channel.update']长度为n。
client.dispatchEvent
dispatchEvent负责派发事件,派发时机为websocket.onmessage触发时,根据后端返回的event.type,调用listens['event.type']数组中的所有事件,同时每次都会调用listens['all']中的所有事件
client.queryChannels
queryChannels负责查询并更新频道列表,返回channels集合,每个元素都是一个channel实例(见下文)
2.3第三步:生成频道实例(channel对象)
频道列表中,每一个频道对应一个channel实例,channel上有几个核心属性和方法如图:
channel.on、channel.off和channel.listens
on、off和listens的原理跟client实例的一模一样。其中,listens事件集合也是通用事件和聊天室事件,在
client.dispatchEvent执行时候执行的,执行原理也一样。
ps:channel主要负责message相关事件
channel.state
state是一个对象,负责记录channel实例的状态,比如改频道的人员数量、未读状态等,在前后端通信后会被更新。