本文介紹 "React + Shadow Widget" 應用於通用 GUI 開發的最佳實踐,只聚焦於典型場景下最優開發方法。分上、下兩篇講解,下篇講述正交框架分析模式與經常使用調測方法。javascript
查閱上篇 請點擊這裏,Shadow Widget 開源項目 在這裏。html
典型的 Flux 框架中,Store 與 View 之間的關係以下:前端
本圖摘自 fluxxor.com
的 「What is Flux?」 一文,Store 中的數據傳遞給一個 Component,這個 Component 又經過 props 屬性驅動多層 Component 子節點來展現界面。在這種數據傳遞關係中,多個 Component 都是 View,但從 Store 得到數據的那個 View 比較特殊,稱爲 "Controller View"(見上圖)。將 Controller View 與 View 對應到 Shadow Widget 的 MVVM 框架,Controller View 就是 VM(ViewModel),由 VM 驅動的子級 Component 就是 V (View)。java
然而現實編程並不是上圖那麼簡單,Controller View 的子節點,也即 View 節點,有時很複雜,其外部若只依賴從上級 props 傳遞下來的數據來驅動渲染,會很彆扭。開發者常不禁自主的放棄 「純淨」 的編程模式,突破限制,讓 View 也從全局變量讀數據,即,變相的把部分數據從 Store 分離出去,改用全局變量表達,或者乾脆讓 View 也直接從 Store 讀數據,而不是隻用 Controller View 代傳的數據。git
Shadow Widget 將問題簡化,既然 Store 主要用於存貯數據,那就還原它的數據特性,做爲數據,在哪兒定義關係不大,直接拿 Component 的屬性存貯數據就好,將 Store 併入 Component 沒有不可逾越的障礙,固然,前提是咱們已設計了 「雙源屬性」 與 「W 樹」 機制。而後,Controller View 及其下級多個 View,合起來視做一個 FB(Functionarity Block),在同一 Functionarity Block Namespace 下用 javascript 定義各節點行爲。把相關節點的投影定義寫一塊兒,很大程度消除了節點間隔閡,由於,你能隨時能夠定義一個變量用來傳數據。github
接本文上篇的例子,假定咱們在原功能基礎上,再增長 「全局配置」 的功能,提供 3 個可選項:「自動選 Celsius 仍是 Fahrenheit 格式」、「固定用 Celsius」、「固定用 Fahrenheit」。其中,第一個選項 Auto(自動選格式)依據瀏覽器特性推斷國別信息,而後智能選擇 Celsius 或 Fahrenheit。編程
新增以下界面設計:bootstrap
相應的,增長一個 Functionarity Block,JS 編碼以下:segmentfault
(function() { // functionarity block var configComp = null; idSetter['config'] = function(value,oldValue) { // ... }; })();
該 FB 的入口節點是 configComp
。再接着細化設計,咱們該將 configComp
定義挪到全局變量定義區,由於該節點在兩個 FB 功能塊都用到。瀏覽器
爲方便講述起見,咱們把這兩個 FB 分別稱爲 config 與 calculator,以 FB 分佈爲橫軸,以 W 樹爲縱軸,W 樹中的節點是層層串聯的,繪製這兩個 FB 的分佈以下圖:
當咱們總體設計 GUI 時,應以 MVVM 方式思考。結合本例,也就是規劃 config 與 calculator 兩個 「功能塊」,肯定各功能塊的入口節點,以及它的上下層串接關係。而處理各個功能塊之間聯動關係時,應切換到 Flux 單向數據流思考方式。
總結一下,整個 HTML 頁面是一顆 DOM 樹,是縱向的,在這顆樹劃分若干功能塊的過程,是基於 MVVM 爲主的設計過程;而處理各功能塊之間橫向聯繫,則以 FRP 思路爲主導。這一縱一橫的思考方式,咱們稱爲 「正交框架」 分析模式。
說明,Flux 是 FRP(Functional Reactiv Programming)開發思想的一種實現,對於 React 開發,上面所提 Flux 與 FRP 基本等效。
至於 FB 之間的功能如何交互,若是處理邏輯簡單,不妨在相關 FB 代碼塊中直接寫代碼,若是邏輯複雜,不妨取相關 FB 的共有父節點做爲入口節點,新設一個 FB 功能塊。取共有父節點的主要做用是,該父節點從建立到 unmount
,能夠覆蓋其下全部節點的生存週期,在它的 idSetter 函數中編程會方便一些。
在可視設計器中開發界面的過程,可能存在破壞式重構,好比你在某個 FB 的入口節點指定 data
屬性值,而後它的子節點根據 data
取值自動生成子節點,若是你給定的 data
初始值格式不對,其下子節點會沒法生成。所給初值不對可能由於設計變化了,你的 data
格式還沒來得及調整。
爲了最大幅度減小上述破壞式重構帶來錯誤,在設計界面時,咱們建議用做驅動源頭的數據初值應取 「空」 值,好比賦給 null
或 []
之類的值。
界面設計過程當中,若想查看不一樣數據初值會驅動什麼樣的界面形態,不妨啓用 W.$dataSrc
定義,好比前面例子界面缺省顯示 Celsius 溫度格式,由於 '.body.calculator.field'
節點的 scale
屬性初值是 'c'
,如今咱們想檢查 scale='f'
界面是否正確。按以下方式使用兩行代碼便可:
if (!window.W) { window.W = new Array(); W.$modules = [];} W.$modules.push( function(require,module,exports) { var W = require('shadow-widget'); var dataSrc = W.$dataSrc = {}; dataSrc['.body.calculator.field'] = { 'scale': 'f' }; });
其中,var dataSrc = W.$dataSrc = {}
表示啓用 W.$dataSrc
,缺省是不啓用的。另外一句 dataSrc['.body.calculator.field'] = { 'scale': 'f' }
,用來預約義哪一個節點要附加哪些屬性的初值。
上面代碼能夠寫入獨立的 js 文件,多個此類 js 文件可構造不一樣的調測場景,而後用 <script>
標籤按需把某一個 js 文件導入到被測頁面。
shadow-bootstrap 新近推出 v1.1 版本,Bootstrap 設計方式在 Shadow Widget 體系獲得完整支持了。
Bootstrap 提供了優秀的前端控件庫,在 shadow-widget 上用 bootstrap 堪稱完美,畢竟上百個 class 類誰都記不住,你們作開發時,要不停的查手冊。用 shadow-widget 的可視化設計器,只需從右側樣板頁拖一個樣板扔進來,就建立你想要的構件了,而後選擇相應節點,把相關屬性配置一下,你的界面很快就作好。
上圖是其中一個樣板頁,該拖入哪一個樣板,看一眼就能區分,再也不受那麼多 class 類名困擾了。
剛開始使用 Shadow Widget 時,你們可能不適應它的可視化設計,容易忘掉幾項設計約束,簡單舉幾個例子:
".body"
節點)下只能擺放面板與絕對定位的構件(如 ScenePage 等),即首層節點要麼是 Panel 類構件,要麼是指定 position='absolute'
的非行內構件。"html."
屬性,要麼使用它的若干子節點,二者只能二選一,若定義子節點了,以 "html."
表示文本將被忽略。總之,與界面設計打交道,設計老是具體的,你要面對各種封裝好的構件,很多構件有特殊要求,《Shadow Widget 用戶手冊》有全面介紹,有必要通讀該手冊。
Shadow Widget 最佳實踐還建議團隊成員要按技能分工,至少有兩個工種,其一是能運用他人已封裝好的 WTC 類或庫化 UI,進行 GUI 開發;其二是爲他人封裝 WTC 類或庫化 UI。前者對技能要求不高,後者則要求深刻掌握 React 與 Shadow Widget 知識。
對於微型團隊,也應按上述分工的思路規劃您的產品開發,由於這兩種分工的目標不一樣,前者着眼短時間目標,儘快把產品作出來,把界面弄漂亮些,後者着眼中長期目標,用封裝庫提升開發複用率。即便是單人團隊,一樣須要分工,無非在時間上錯開,一段時間承擔一種角色,另外一段時間換一個角色。
Shadow Widget 當前的 WTC 類與界面庫還不夠豐富,但它的架子已搭好,起點不低。它的定製擴展能力出色,已經過一些上規模代碼的產品檢驗,如 shadow-bootstrap
, pinp-blogs
等,具有必定成熟度。咱們有理由相信,這個產品會隨着擴展庫逐漸增多,前景愈來愈光明。
(本文完)