每天定時分享技術幹貨/優秀開源/技術思維
前言
❝
無論
lowcode
再怎麼????x,都避免不了對于複雜頁面或者說特定頁面的源碼開發
❞
此篇作為階段性總結以及對 BeeMa 架構開發輔助插件的鋪墊。
❝
以下介紹,主要是針對使用Rax 、TypeScript 的
H5 MPA
開發總結。
❞
丐版

通常編碼
MPA
應用,都是在
pages
下新增相應
page
,然後在裡面堆
components
。對于ajax 接口聯調一般都是在
componentDidMount
或者
useEffect
中。雖說如此,但是比較寬泛。
團隊中大多使用 rax 編碼,在日常編碼工作中就是
fn(state)=>UI
的過程,是以在歸類下來主要工作無非:
-
- 「
」 「提供聚合」index.tsx
- 「請求接口拿到字段傳遞給各個元件」
- 「元件展示、消化内部狀态 or 協同合作(通信)」
現狀
如果沒有規範的限制,那麼每個人的風格都差别較大
可以看到,前端的業務編碼無非就是如上三個問題,但是每個同學處理的方式都迥然不同,導緻業務中每接手一個項目改動别的同學代碼都需要花費一定能的時間去消化原有邏輯。
并且!如果涉及到多人合作的頁面,可能還會有大量的代碼沖突(「頁面邏輯并未高度解耦」)
問題與挑戰
總結如上源碼開發中團隊合作遇到的問題:
-
- 編碼風格差異較大,接手老項目需要花費一定時間消化代碼邏輯
- 業務子產品耦合度高
- Bundle 較大,首屏加載、
缺失codespliting
- 頁面容器缺乏一緻性,能力參差不齊
而針對如上問題,如果我們需要提供一套架構來解決這類問題,那麼至少我們需要提供:
-
- 頁面容器(管理子產品、基本頁面功能封裝)
- 狀态管理方案
- 子產品加載方案(子產品高度解耦,避免多人協作沖突)
- 如上功能抽成元件,代碼倉庫更專注于業務開發
Action
基礎容器
從之前做過的項目中,我們總結容器應該具備如下能力:
API 說明
屬性 | 含義 | 類型 |
title | 标題 | string |
renderPlaceholder | 渲染占位層(loading) | ()=>FunctionComponent |
showPlaceHolder | 是否展示占位層(isLoading) | boolean |
hiddenScrollToTop | 隐藏回到頂部 | boolean |
toTopProps | 回到頂部元件的屬性 | IScrollToTopProps |
renderHeader | 渲染頭部元件 | ()=>FunctionComponent |
renderFootr | 渲染底部元件 | ()=>FunctionComponent |
customStyles | 自定義容器樣式 | {contentWrapStyles,headWrapStyles,bottomWrapStyles} |
onEndReachedThreshold | 距離底部多少距離開始觸發 endReached | Number |
IScrollToTopProps
屬性 | 說明 | 類型 |
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 |
如上容器元件的封裝,就提供了基本的容器能力。面對大部分的業務開發,基本都是能夠滿足需求的。
❝
再次強調!!!「編寫業務頁面,其實完全可以把整體工作分為兩趴:」
- 「format 資料」
- 「拿資料渲染 UI」
❞
❝
「是以文章後面介紹的就是狀态管理工具選型,以及如何整理狀态,最後,如何加載子產品」
❞
狀态管理
有了基礎容器提供的底層能力,再回想我們使用
react
、
vue
還是
rax
開發前端頁面,其實都是「狀态驅動 UI 的過程」,是以針對複雜業務的場景,狀态管理自然必不可少。
基于現有的
hooks
技術方案,天然就存在狀态管了解決方案:
useRedux
,但是考慮到子產品之間的高度解耦,還是非常有必要對
redux
進行改動,讓其支援中間件、
compose
、
combineReducers
等特性。是以針對第一版的架構設計,自己封裝了一份狀态管理方案:從 redux 的範式中搬個輪子做源碼項目的狀态管理
但是目前集團内,
ice
提供了一套更加簡易的狀态管理封裝,iceStore 并且 rax 也提供了支援。是以自然還是跟着集團的源碼方向走,這裡我們的狀态管理,最終選擇了使用
iceStore
的解決方案
對于狀态管理,「考慮到子產品的高度解耦,約定每一個子產品,對應着狀态樹的一個分支」, 簡而言之,就是新增一個子產品,要新增對應子產品的
model
如上優點:
-
- 狀态統一管理,簡單頁面隻需管理自己的 model 對應的
和state
即可dispatchers
- 跨子產品通信可通過引入對應子產品的
即可dispatchers
- 頁面通用資料,比如寶貝 id 等,可通過
,由架構層面統一分發到每一個子產品中(子產品加載部分介紹具體實作)common model
狀态分發
講解狀态分發的前提應該先介紹下接口資料的請求配置。其實也比較簡單,就是一個
mtop
(
ajax
)請求拿到資料而已
架構中,「将請求封裝到「
utils
」裡面,然後在自定義「
hooks :useDataInit**
」中調用分發狀态」
請求接口資料
❝
在源碼架構初始化出來是一個模拟的請求,資料來自「page-name/mock/index.json」
❞
狀态分發 use-data-init.ts
在自定義
hooks
中,拿到資料後,根據「子產品化字段」,分發到對應的元件裡面。
如上,「我們已經完成了我們裝備整個應用(頁面)的狀态的工作」,下面我們的「重點就是如何合理的根據狀态樹去加載子產品」
子產品加載
子產品加載,按照之前較為“随意”的編碼方式,是根據各自風格,「往 index.tsx 中一股腦的堆放,加持着各種 ifElse 的判斷」這樣存在的弊端如下:
-
-
入口雜亂index.tsx
- 頁面耦合度較高,多人協作存在沖突
- 久而久之可能會導緻
較長,邏輯複雜index.tsx
針對如上問題,我們希望:
-
- 子產品基于配置
- 如果不涉及到公共邏輯或者頁面級别的部分,
盡可能大家都不會涉及到修改index.tsx
- 子產品能夠異步加載,支援
code splitting
目錄
❝
src/page-name/components/
❞
小總結
-
- 編寫業務頁面,工作分為兩步:1、拿到“自己滿意”的
。2、根據state
去渲染state
。所謂的各種互動也隻是修改對應的UI
而已state
- 初始化狀态在
裡通過調用接口拿到資料,并且分發到各個子產品裡面。組成我們“想要”的狀态樹。use-data-init
-
根據拿到的狀态樹然後基于index.tsx
來決定如何加載元件config.ts
- 底層能力通過
元件支援pageContainer
- 狀态管理方案選擇
,對應的store
除了model
和pageState
,其他就是每一個業務子產品common
重點強調
注釋
Ts 中「注釋即文檔」。雖然子產品高度解耦,但是哪怕自己再熟悉的子產品,随着時間推移也有生疏的時候,是以盡可能的做到「子產品聲明的每一個字段都加以注釋」
state 分支對應的子產品需要與 config.ts 中配置保持一緻
❝
詳細限制詳見:拍賣源碼架構在詳情頁上的探索
❞
之是以不想詳細介紹限制,是因為這裡提供了一系列 vscode 插件,「按照插件的提供的功能去開發,即可消化架構層面帶來的限制」
解決方案
❝
詳細使用說明,下回分解~
❞
建立應用
createPro.gif
❝
支援 pc、無線、元件等應用腳手架 模闆 EMS 配置
❞
建立頁面
❝
以 h5 源碼舉例
❞
createPage.gif
-
- 根據應用類型,擷取對應頁面頁面腳手架
- 基礎資訊支援多種模闆語言配置
- 移動端支援基礎UI配置(通用頭、漸變背景、底部按鈕等正常布局 UI)
- 支援頁面基礎資訊修改
子產品配置
-
- 新增、删除子產品
- 子產品支援首屏元件以及按需加載元件
- 子產品拖拽排序
BeeMa 大綱
BeeMa 大綱
❝
友善快捷定位核心功能開發,近乎 96%的功能可以 focus 到此大綱中完成