前言
前段時間發在朋友圈的一句話:各種自主搭建的平臺,想起好多年各種DIY博客,行業門戶網站,本質不變,變的是實現的手段了。
正文從這開始~~
本文主要介紹了基於 React 構建可視化編輯平臺的實踐,包括對可視化拖拽佈局、在線編輯、同構直出的實現。
背景
目前,HRG 的英才校園在線招聘業務有大量的企業定製化需求,企業在英才校園做招聘,同時也希望有自己的招聘主頁,每年都會招聘一部分兼職同學來開發這類的招聘主頁,這類招聘主頁通常不復雜,但是如果全部需要前端同學實現的話,還是很耗時費力的,我們希望能通過技術手段不斷的提升這類業務的交付效率。
提效規劃
定製頁相關的項目,早期是通過靜態頁來做的,純靜態頁對開發者來說上手容易,但是很難做組件化,上線流程完全靠手工,成本太高,所以我們計劃逐步推進通過可視化編輯提升效率。
項目整體分了兩期:
一期,實現了可視化的在線編輯、發佈,支持流式佈局、絕對定位佈局、同構直出、動畫,提供了通用的組件庫。
二期,支持組件可擴展,提供組件開發工具,組件市場,三期仍在完善階段,暫未發佈。
系統演示
首先看下我們的系統演示,然後再逐步分析深入,主要是可視化編輯系統開發思路,以及關鍵模塊的實現。
系統維度分析
針對可視化編輯平臺,我們做了一些調研,有一些思想我們覺得挺有意義,這裡分享一下,參考文章見參考文獻。
我們的系統,對標上面的維度應該下面三項:
系統功能
Component Tree 編輯,核心功能為頁面可視化佈局設計
頁面由組件組成,組件可以支持嵌套,目前組件是通用的組件,後期會支持擴展,組件可以承載業務邏輯。
提供了拖拽佈局支持,支持流式佈局,絕對定位佈局。
面向客群
前端小白,核心訴求是交互性高,所見即所得的編輯方式
目前是組內兼職的同學在用,有一定的前端佈局基礎,理解每個組件的使用方式。
如果想降低對用戶的要求,比如對普通用戶,那麼就要提供模板支持,對普通用戶而言,改改背景圖,換個圖片,編輯下文字就夠用了,越是要降低對用戶的要求,越是要固化一些設計和數據模型。
前端框架組件,依賴工具提供組件,編輯效率高,業務邏輯封裝度高
目前系統的自由度是組件級別,內置了通用的組件,包括:
- 基礎組件:圖片、文本、表格、模板組件
- 複雜組件:數據列表、跑馬燈、輪播圖、表格
- 佈局:錨點佈局、標準佈局、選項卡布局
- 容器:上下流(塊),左右流(內聯塊),自由容器(絕對定位佈局)
這些組件是內置到系統的,二期的組件市場,目標是組件可擴展,組件可以承載業務,業務邏輯封裝度更高些,方便使用。
技術實現
系統採用技術棧如下:
- 前端:React + Redux + ImmutableJs + ReactDND + Antd
- 後端:Node Express + MongoDB + Redis
可視化佈局
首先,需要定義渲染UI的數據結構,通常這種UI的數據都是樹形的結構,可以用一個大的 JSON 來表示,然後遞歸渲染。
類似如下的結構:

節點使用類似 React 的虛擬 DOM 結構:
- Type :組件類型
- Props :組件屬性
- Children:組件的子節點列表
- Sort:排序號
由於直接使用樹形的的結構,對節點的增刪改查不友好,所有進行了扁平化處理,將樹拆成了兩個結構:
結構一:

存儲節點的關係,類似一個數據庫的二維表,描述節點的父子關係,方便修改父子結構,同級排序。
結構二:
存儲節點的數據,通過 ID 可以獲取節點數據,方便節點數據更新。
其次,定義好數據結構以後,就是渲染頁面了,將上面的兩個數據合併組成樹形結構,然後遞歸遍歷創建組件對象。
創建組件的時候,需要獲取對應的組件類型,比如導航組件,輪播圖組件,所以需要一個組件的類型映射表,根據組件的 Type 獲取對應的類型,創建實例。
還有組件的佈局能力,佈局功能抽到容器裡,所以組件在創建的時候會包裹對應的容器,組件的定位由容器負責,不同的容器提供不同的功能,容器由高階組件提供。
如下圖所示:
圖中 typeFactory 負責組件的創建,創建組件的同時包裹對應的高階組件,
這裡是組件在編輯狀態的渲染過程,發佈以後,考慮的渲染的性能,預先創建了組件的樹形結構。
最後,實現拖拽佈局,佈局完全是容器來負責,拖拽過程的位置檢測由容器來實現,通過鼠標位置確定組件的安放位置,修改描述組件關係的數據,觸發重新渲染。
流式佈局演示:
自由佈局演示:
前面說了組件的佈局,除了佈局,還要對組件的屬性進行編輯,編輯也是通過容器來實現的,通過高階組件來複用。
組件也需要遵守一個規範,方便獲取組件的屬性列表,為組件增加額外的靜態屬性來說明組件的屬性說明。
系統提供了組件屬性編輯器,同時可以支持擴展出其他自定義編輯器。
同構直出
因為定製頁是需要 SEO 的,所以要做服務器端渲染,也就是要做同構直出。
做同構直出需要考慮以下內容:
- 全局的 Store(Redux)
- 組件內 CSS 抽取(Glamor)
- 針對 Node 端單獨構建一個組件庫,忽略組件內 less 的引用
- 設置 externals 避免包過大
- 組件內異步獲取的數據,通過為組件加靜態屬性 getInitProps(參考Next框架)
Store 中存儲了組件樹和組件屬性數據,直出的不僅僅是 HTML,還包括對應的 CSS,這裡使用 css in js 方案 Glamor,渲染 HTML 的同時,也可以提取對應的 CSS。
下面是同構直出的大致流程:
同構直出的渲染結果:
為了減小首次渲染頁面的體積,並沒有把狀態數據內嵌到頁面裡,而是提供了一個狀態的的請求鏈接,異步加載狀態數據。
一階段完成以後,開始上線運行支持業務,目前已經支持 100+ 的定製頁項目,通過在線編輯、修改、發佈,節約了大部分編碼、構建、發佈的時間,開發效率大幅提升。
組件可擴展
由於一階段是內置的組件庫,包括通用組件以及定製頁業務相關的組件,二階段希望能實現組件可擴展,提升平臺的應用範圍,實現頁面級的組件,增強易用性。
組件市場
組件市場是一個組件的集合,提供可選的組件,組件的粒度可以開發者控制,可以是組件級,也可以是頁面級,可以內嵌業務,或者是通用的組件。
組件開發CLI工具
提供組件開發腳手架,本地開發、調試環境,可以發佈組件到組件市場。
組件動態加載
為了動態加載組件,我們開發了模塊加載器 BondJs,可以動態加載頁面依賴的所有組件,將組件註冊到系統裡。
目前組件市場還處於完善階段,計劃年底上線,磨合一段時間,後期希望可以積累更多的模板,接入其他業務,能提升運營類項目的效率。
關於第二階段的後續有機會可以再詳細說明,這裡不展開了。
易用性分析
目前平臺是給內部開發者使用,因為編輯自由度高,需要有一定的前端基礎,系統也提供了模板功能,直接從模板編輯相對易用一些,不過,仍是對頁面內元素的編輯,對運營/產品/企業用戶來說還是有一定的難度。
對普通用戶來說,最容易懂的模型不是頁面的元素,而是業務模型,比如用戶信息、企業信息、職位信息這一類更貼近用戶的模型,所以後期組內同學和後端同學一起開發基於後端模板的解決方案,這個方案的優點是可以利用企業招聘方的數據模型,比如企業介紹、職位列表等數據,再提供多個後端預置模板,企業只需要維護自己的信息,然後選擇一個模板即可,可以滿足對定製頁要求不那麼高的用戶。
靈活性和易用性是需要平衡的,越靈活往往易用性比較差,一般是通過預定義來說提升易用性,細粒度的組件很靈活,但是易用性差,後續可以開發內嵌業務的頁面級組件,來提升易用性。
總結
目前,整個編輯平臺已經支持了 100+ 的項目,針對複雜度不高的項目可以很大提升開發效率,整個項目因為是 Side Project ,一邊支持業務一邊開發,所以花了不少時間,回過頭來看,做這類項目,首先要有明確的目標和受眾,是為開發者賦能,還是服務普通用戶,可視化佈局也不是銀彈,所以要想好真正影響效率的地方。比如有些項目開發快,但是面對用戶的頻繁修改需求,效率也很難提升,反過來要控制用戶的需求變更,如果客戶要求不高,直接給個默認模板就可以,或者提供多樣的選擇,讓用戶選擇相對滿意的模板即可。
後期組件市場上線,希望可以接入不同的業務線,提供更多面向業務的組件或者頁面模板,提升系統的應用廣度,提升運營類項目的開發效率。
原文:https://zhuanlan.zhihu.com/p/94016600
閱讀更多 IT技術之家 的文章