Web UI組件化最佳實踐的思考
前端組件化的幾種思路
- 重客戶端的SPA模式,將大量的邏輯和數據處理放在客戶端,服務器端提供JSON數據
- 服務器端處理業務邏輯,客戶端只負責兩個事情:顯示和發送數據到服務器端,服務器來調度UI的顯示
- 混合模式,混合使用以上兩種方案,交叉使用rjs + html + json
第一種方式現在比較流行,也有很多比較的框架支持,比如 React, angularjs 等。優點是,速度很快,交互體驗比較好,UI容易組件化。缺點是 客戶端非常重,需要編寫大量的JS代碼。對程序員的要求也很高,需要非常熟悉服務器端和客戶端代碼。
第二種方案是Rails推薦的方案。優點是開發速度非常快,但是用不好。因爲Rails 太靈活,服務器端可以向客戶端發送各種格式的數據:比如 HTML, JSON, JS。並且,這種方案 UI 特別不容易組件化。如果用官方傳統的方案使用 render partial 方案會讓view層代碼膨脹,並且定製化也不好做,需要做大量的if else 判斷。
第三種方案在一個無序的項目中經常出現。這樣的後果是,項目代碼膨脹,維護性很差,並且UI很難組件化,重用的可能性幾乎爲零。
我的實踐
我以前非常喜歡的方案是重客戶端的方案, Rails/Express
只負責提供數據和業務邏輯,不負責UI的生成和流程。因爲這種方案有一個非常大的優勢,就是它是一種非常標準的Clint - Server
開發模式。客戶端的代碼甚至可以直接打包成App client
(這是一種非常理想的狀態)。在實踐的過程中,我發現了有很多問題:首先,需要熟悉客戶端的框架,需要較多的技術棧,學習曲線陡峭,不僅僅需要熟悉Rails,還需要熟悉JS的技術棧,比如webpack打包,react 等框架;第二,富客戶端框架與Rails整合複雜;第三,Rails 的功能弱化了,無法使用Rails提供的大量方便的特性。
第二種方案是對Rails
這種的重服務器的框架來說,是一種可選的方案。但如果只使用Rails自帶的View + Helper
方式很難實現UI組件化的問題。所以,我們需要新的解決方案,它應該滿足如下幾個條件:
1. UI可以重用:這是核心需求,只有UI組件可以重用,才能提升生產力,提高產品質量
2. UI的樣式可以定製化:可以定製化纔可以擴展項目的UI庫,所以也很重要
3. 不同UI組件可以通信:不同組件之間的通信是一個非常常見的case,這是提升用戶體驗的關鍵
4. 開發速度一定要快:就是要使用方便
5. 與Rails整合比較好:這是後臺服務器的技術決定的,不同的服務器端框架需要做對應的適配
一個簡單的例子: Todo List
我打算用一個非常簡單的例子: Todo List, 來實踐上面定的方案。
如下圖所示,我打算做一個簡單的Todo list。它只有一個功能,在input框中輸入任務名稱,下面的任務列表會自動刷新。
分析:
1. 可以將頁面分成幾個部分:TodoContainer
和 Todo
2. TodoContainer
是組合容器,不負責具體的UI的顯示
3. Todo
是普通的UI組件,負責具體的UI的顯示,但不負責UI直接的交互
4. UI組件直接的交互通過Rails
完成
如下是我的架構設計圖
從圖中可以看出,UI組件直接的更新是通過服務器來觸發的,不同組件不要在客戶端通信。這樣就降低了組件的複雜度,並且解耦合。
我實踐了 Rails + RJS + cells 能很好的滿足我的要求。代碼在 https://github.com/chucai/cell_case 。 下面我簡單的說明一下我的實踐流程:
- 初始化項目
rails new cell_case
安裝 guard , guard-livereload
主要是用在修改服務器端代碼,可以自動刷新瀏覽器。這是web開發必備神器,特別是在有雙屏的條件下,可以極大的提供我們的開發效率。安裝 livereload 的 chrome 插件
3.1 安裝地址
https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei
3.2 配置
訪問http://localhost:3000
,然後在瀏覽器的右上角,點擊livereload
的加載按鈕。
這一步很關鍵,否則自動刷新將無法使用。
3.2 啓動 guard
guard
安裝
cells
Rails UI 組件化的一個庫新建一個Model - Todo
rails g cell todo
- 創建首頁
rails g controller dash index
- 創建第一個容器組件 - TodoContainerCell
rails g cell todo_container
- 使用容器組件組合其他組件
其中有幾個值得注意的:我們在傳遞額外的數據給cell組件的時候,可以使用 Hash
的方式,這樣數據會保存在Cell
對象的options
中。
總結
不足之處在於 cell
組件過於簡單的,沒有不同的角色,比如 Container
組件,功能太單一了,只是一個簡單的View-Model
。如果要深度使用,還需要在cells
的基礎中進行定製化。cells
的代碼比較簡單,可以在這個基礎上做一些擴展。