
前言
上文介绍了数据层SDK和UI组件的开发,大家了解了系统的分层,分别知道各个层如何实现,这章主要和读者一起串联各个模块,介绍里面串联的设计技巧,完整的搭建一个原型聊天系统,感兴趣的同学可以在这基础上扩展。
技术栈准备
- Alibab/RAX 技术栈,开源地址
- Yeoman 使用 自建
generator-rax-component脚手架构建聊天项目环境 - 数据SDK开发章节封装的
tbms-brandsdk-yunxinNPM包,提供标准SDK。 - UI组件章节封装的
tbms-components的NPM包,提供UI组件。
相关技术栈源码
generator-rax-component: https://github.com/ge-tbms/generator-rax-component
tbms-brandsdk-yunxin: https://github.com/ge-tbms/tbms-brandsdk-yunxin
tbms-components: https://github.com/ge-tbms/tbms-components
数据和UI层结合
整体结合思路,通过数据层SDK的标准数据结构和回调,通过 dispatch 和 UI层组件结合起来,在封装消息HOC组件, 实现所见即所得。
数据层 + UI层 => 聊天系统

聊天系统源码地址:
标准SDK使用
初始化SDK
import {createElement, Component, render, findDOMNode} from 'rax';// 1、数据层沉淀的 `tbms-brandsdk-yunxin` SDK NPM包import YUNXINSDK from 'tbms-brandsdk-yunxin';// 2、组件容器class App extends Component {constructor() {super();// 3、初始化SDK,初始化参数及标准事件回调this.sdk = new YUNXINSDK({uid: uid, // 登录用户IDtouid: touid, // 目标用户IDonmsg: this.onMsg.bind(this), // 收到及时消息回调onofflinemsg: this.onOfflineMsg.bind(this), // 收到离线消息回调onerror: this.onError.bind(this), // 错误情况回调onconversation: this.onConversation.bind(this), // 建立或者更改会话回调onsystemmsg: this.onSystemMsg.bind(this), // 系统消息回调onlogin: this.onLogin.bind(this) // 登录信息回调});}}
注释:在组件构造器生命周期中初始化SDK,初始化参数,回调各种标准事件。
编写 onmsg 回调
// 通过scrollTop 设置滚动偏移高度const SCROLLTOP = 100000;class App extends Component {onMsg(msg) {const MessageList = this.state.MessageList;componentParser.dispatch(msg, this.conversation).then(ctx => {const ItemComponent = ctx.ItemComponent;// 设置页面titlethis.titleParse(ctx.message);// push消息组件MessageList.push(<ItemComponent {...ctx.message} />);// 更新节点this.setState({MessageList}, () => {// 滚动到页面底部this.horizontalScrollView.scrollTo({y: SCROLLTOP});})})}}
注释:1. 维护消息队列,通过上文提到解析器模块流转数据,从而在 then 中获取相应的组件。2. 设置标题,Push 消息组件到 MessageList 消息队列中。3. setState更新状态,在更新状态之后把导航栏至底部。
编写 offlinemsg 回调
class App extends Component {onOfflineMsg(msg) {const MessageList = this.state.MessageList;if (_.isObject(msg)) {componentParser.dispatch(msg, this.conversation).then((ctx) => {const ItemComponent = ctx.ItemComponent;// 1、通过unshift顶部队列MessageList.unshift(<ItemComponent {...ctx.message} />);// 2、更新节点this.setState({MessageList,}, () => {// 3、导航栏定位到相应位置const scrollTop = findDOMNode(this.refs['body']).offsetHeight - this.containerHeight;this.horizontalScrollView.scrollTo({y: scrollTop});})})} else {// 4、没有历史消息(离线消息),则为暂无消息this.setState({isEmpty: true})}}}
注释:和 onmsg 差别在于顶部更新消息队列,同时导航栏定位到相应位置。如果没有历史消息(离线消息)则设置为为空表现。
编写 onConversation,onLogin 和 onError 回调
import merge from 'lodash/merge';import Toast from 'universal-toast';class App extends Component {onConversation(conversation) {// 1、存储会话信息this.conversation = merge(this.conversation, conversation);}onLogin() {Toast.show('登入成功');// 2、登入成功,则开始获取历史消息this.sdk.getHistoryMessage({scene: 'p2p',to: this.conversation.touid,})}onError(err) {// 统一错误信息处理Toast.show(JSON.stringify(err));}}
注释:onLogin 登录成功之后,拉取历史消息
UI层使用
整体UI结构
class App extends Component {renderPlugin() {// 1、插件选择,原型聊天实现 emoji 表情插件if (this.state.pluginVisible === 'emoji') {return <EmojiPlugin onChange={this.handleEmojiChange} onSend={this.handleSendText} type="ww" />;} else {return null;}}render() {return (// 2、聊天View容器<View style={styles.container}>// 3、消息流滚动组件<ScrollViewstyle={styles.containerBody}ref={(scrollView) => {this.horizontalScrollView = scrollView;}}><View ref="body">{this.state.MessageList}</View></ScrollView>// 4、输入框组件<InputText text={this.state.inputText}onPluginChange={this.handlePluginChange}onFocus={this.handleFocus}onChange={this.handleChangeText}onSubmit={this.handleSendText}showPlugin={false}/>// 5、插件组件{this.renderPlugin()}</View>);}}
注释:整体聊天UI结构主要分为三个区块:消息流区域,输入框区域和插件区域。
插件和输入框组件通过自定义组件包 rax-tbms-chat-plugin 引入。
消息发送
class App extends Component {handleSendText = (text) => {const content = (text || this.state.inputText).trim();// 1、判断内容是否为空if (content) {// 2、 发送文本消息this.sdk.sendMsg({type: 'text',content: content});this.setState({inputText: ''})} else {Toast.show('亲,输入内容不能为空哦!')}}}
注释:通过 sdk 封装的 sendMsg 发送消息,同时也可以指定其他数据类型(例如image,card等数据类型)。
结语
这个章节把之前封装的模块进行了串联,总结起来,作者认为做好分层,明确每一层的职能和划分, 基本可以从容面对一个负责的系统。
就像IM聊天,我们把复杂的数据逻辑放在了SDK层,同时接口数据方面做了单元测试来保证稳定性。 在UI方面,拆分了单元化组件,最后再把两者结合起来构建了一个聊天系统。
复盘提升
这是一次完整的项目实践过程,用到了前端各种技术栈和思考模型。同时小册精讲了各个知识点,我们需要辩证的来看各个知识点解决的问题,最重要的是通过项目实践,形成体系化的思考模型。
如下图所示:原先我们是发散性思维模式到现在的体系化思维模式。

