❝原文地址:Nealyang/PersonalBlog ❞
❝无论
lowcode再怎么🐂x,都避免不了对于复杂页面或者说特定页面的源码开发 ❞
之前也有写过相关文章总计:一张页面引起的前端架构思考,但是更多的是介绍How,并没有介绍到 Way,经过了一年的使用(rax 1.x 体系也在完善),必然也会伴随着一部分的调整。此篇作为阶段性总结以及对 BeeMa 架构开发辅助插件的铺垫。
❝以下介绍,主要是针对使用Rax 、TypeScript 的
H5 MPA开发总结。 ❞

通常编码MPA 应用,都是在 pages 下新增相应page,然后在里面堆components。对于ajax 接口联调一般都是在 componentDidMount 或者 useEffect 中。虽说如此,但是比较宽泛。
团队中大多使用 rax 编码,在日常编码工作中就是 fn(state)=>UI的过程,所以在归类下来主要工作无非:
index.tsx」 「提供聚合」如果没有规范的约束,那么每个人的风格都差别较大


可以看到,前端的业务编码无非就是如上三个问题,但是每个同学处理的方式都迥然不同,导致业务中每接手一个项目改动别的同学代码都需要花费一定能的时间去消化原有逻辑。
并且!如果涉及到多人合作的页面,可能还会有大量的代码冲突(「页面逻辑并未高度解耦」)
总结如上源码开发中团队合作遇到的问题:
codespliting 缺失而针对如上问题,如果我们需要提供一套架构来解决这类问题,那么至少我们需要提供:

从之前做过的项目中,我们总结容器应该具备如下能力:
属性 | 含义 | 类型 |
|---|---|---|
title | 标题 | string |
renderPlaceholder | 渲染占位层(loading) | () => FunctionComponent |
showPlaceHolder | 是否展示占位层(isLoading) | boolean |
hiddenScrollToTop | 隐藏回到顶部 | boolean |
toTopProps | 回到顶部组件的属性 | IScrollToTopProps |
renderHeader | 渲染头部组件 | () => FunctionComponent |
renderFootr | 渲染底部组件 | () => FunctionComponent |
customStyles | 自定义容器样式 | {contentWrapStyles,headWrapStyles,bottomWrapStyles} |
onEndReachedThreshold | 距离底部多少距离开始触发 endReached | Number |
属性 | 说明 | 类型 |
|---|---|---|
bottom | 距离底部距离 | number |
zIndex | zIndex | number |
icon | 图片 icon 地址 | string |
darkModeIcon | 暗黑模式的 icon 图片地址 | string |
iconWidth | icon宽度 | number |
iconHeight | icon 高度 | number |
threshold | 滚动距离(滚动多少触发) | number |
animated | 点击回滚到顶部是否有动画 | boolean |
right | 距离容器右侧距离 | number |
onShow | 展示回调 | (...args) =>void |
onHide | 消失回调 | (...args) =>void |
名称 | 含义 | 参数 |
|---|---|---|
SCROLL | 滚动事件 | scrollTop 具体顶部距离 |
TRIGGER_ERROR | 触发 error 界面 | |
END_REACHED | 触底事件 | |
RESET_SCROLL | 重置滚动,重新计算容器高度 | |
ENABLE_SCROLL | 禁止滚动 | true/fase |
如上容器组件的封装,就提供了基本的容器能力。面对大部分的业务开发,基本都是能够满足需求的。

❝再次强调!!!「编写业务页面,其实完全可以把整体工作分为两趴:」
❞
❝「所以文章后面介绍的就是状态管理工具选型,以及如何整理状态,最后,如何加载模块」 ❞

有了基础容器提供的底层能力,再回想我们使用 react、vue 还是 rax 开发前端页面,其实都是「状态驱动 UI 的过程」 ,所以针对复杂业务的场景,状态管理自然必不可少。
基于现有的 hooks 技术方案,天然就存在状态管理解决方案:useRedux ,但是考虑到模块之间的高度解耦,还是非常有必要对 redux 进行改动,让其支持中间件、compose、combineReducers等特性。所以针对第一版的架构设计,自己封装了一份状态管理方案:从 redux 的范式中搬个轮子做源码项目的状态管理
但是目前集团内,ice 提供了一套更加简易的状态管理封装,iceStore 并且 rax 也提供了支持。所以自然还是跟着集团的源码方向走,这里我们的状态管理,最终选择了使用 iceStore 的解决方案
对于状态管理,「考虑到模块的高度解耦,约定每一个模块,对应着状态树的一个分支」 , 简而言之,就是新增一个模块,要新增对应模块的 model

如上优点:
state 和 dispatchers 即可dispatchers 即可common model ,由框架层面统一分发到每一个模块中(模块加载部分介绍具体实现)讲解状态分发的前提应该先介绍下接口数据的请求配置。其实也比较简单,就是一个 mtop(ajax)请求拿到数据而已
架构中,「将请求封装到 「utils」 里面,然后在自定义 「hooks :useDataInit**」 中调用分发状态」

❝在源码架构初始化出来是一个模拟的请求,数据来自 「page-name/mock/index.json」 ❞

在自定义 hooks 中,拿到数据后,根据「模块化字段」,分发到对应的组件里面。


如上,「我们已经完成了我们装备整个应用(页面)的状态的工作」,下面我们的「重点就是如何合理的根据状态树去加载模块」
模块加载,按照之前较为“随意”的编码方式,是根据各自风格,「往 index.tsx 中一股脑的堆放,加持着各种 ifElse 的判断」 这样存在的弊端如下:
index.tsx 入口杂乱index.tsx 较长,逻辑复杂
针对如上问题,我们希望:
index.tsx尽可能大家都不会涉及到修改code splitting❝src/page-name/components/ ❞

state 。2、根据 state 去渲染 UI。所谓的各种交互也只是修改对应的 state 而已use-data-init 里通过调用接口拿到数据,并且分发到各个模块里面。组成我们“想要”的状态树。index.tsx 根据拿到的状态树然后基于 config.ts 来决定如何加载组件pageContainer 组件支持store,对应的 model 除了 pageState 和 common,其他就是每一个业务模块Ts 中「注释即文档」。虽然模块高度解耦,但是哪怕自己再熟悉的模块,随着时间推移也有生疏的时候,所以尽可能的做到「模块声明的每一个字段都加以注释」


❝详细约束详见:拍卖源码架构在详情页上的探索 ❞
之所以不想详细介绍约束,是因为这里提供了一系列 vscode 插件,「按照插件的提供的功能去开发,即可消化架构层面带来的约束」
❝详细使用说明,下回分解~ ❞


createPro.gif
❝支持 pc、无线、组件等应用脚手架 模板 EMS 配置 ❞
❝以 h5 源码举例 ❞

createPage.gif



BeeMa 大纲
❝方便快捷定位核心功能开发,近乎 96%的功能可以 focus 到此大纲中完成 ❞