摘要:本文介紹應(yīng)用于通用開(kāi)發(fā)的最佳實(shí)踐,只聚焦于典型場(chǎng)景下最優(yōu)開(kāi)發(fā)方法。結(jié)合的可視化設(shè)計(jì)新近推出版本,設(shè)計(jì)方式在體系得到完整支持了。注此項(xiàng)為建議,不強(qiáng)制面板之下不能直接放行內(nèi)構(gòu)件,要在面板下放置類構(gòu)件后,才能放類構(gòu)件。
本文介紹 "React + Shadow Widget" 應(yīng)用于通用 GUI 開(kāi)發(fā)的最佳實(shí)踐,只聚焦于典型場(chǎng)景下最優(yōu)開(kāi)發(fā)方法。分上、下兩篇講解,下篇講述正交框架分析模式與常用調(diào)測(cè)方法。
查閱上篇 請(qǐng)點(diǎn)擊這里,Shadow Widget 開(kāi)源項(xiàng)目 在這里。
1. Controller View 與 View典型的 Flux 框架中,Store 與 View 之間的關(guān)系如下:
本圖摘自 fluxxor.com 的 “What is Flux?” 一文,Store 中的數(shù)據(jù)傳遞給一個(gè) Component,這個(gè) Component 又通過(guò) props 屬性驅(qū)動(dòng)多層 Component 子節(jié)點(diǎn)來(lái)展示界面。在這種數(shù)據(jù)傳遞關(guān)系中,多個(gè) Component 都是 View,但從 Store 獲得數(shù)據(jù)的那個(gè) View 比較特殊,稱為 "Controller View"(見(jiàn)上圖)。將 Controller View 與 View 對(duì)應(yīng)到 Shadow Widget 的 MVVM 框架,Controller View 就是 VM(ViewModel),由 VM 驅(qū)動(dòng)的子級(jí) Component 就是 V (View)。
然而現(xiàn)實(shí)編程并非上圖那么簡(jiǎn)單,Controller View 的子節(jié)點(diǎn),也即 View 節(jié)點(diǎn),有時(shí)很復(fù)雜,其外部若只依賴從上級(jí) props 傳遞下來(lái)的數(shù)據(jù)來(lái)驅(qū)動(dòng)渲染,會(huì)很別扭。開(kāi)發(fā)者常不由自主的放棄 “純凈” 的編程模式,突破限制,讓 View 也從全局變量讀數(shù)據(jù),即,變相的把部分?jǐn)?shù)據(jù)從 Store 分離出去,改用全局變量表達(dá),或者干脆讓 View 也直接從 Store 讀數(shù)據(jù),而不是只用 Controller View 代傳的數(shù)據(jù)。
Shadow Widget 將問(wèn)題簡(jiǎn)化,既然 Store 主要用于存貯數(shù)據(jù),那就還原它的數(shù)據(jù)特性,作為數(shù)據(jù),在哪兒定義關(guān)系不大,直接拿 Component 的屬性存貯數(shù)據(jù)就好,將 Store 并入 Component 沒(méi)有不可逾越的障礙,當(dāng)然,前提是我們已設(shè)計(jì)了 “雙源屬性” 與 “W 樹” 機(jī)制。然后,Controller View 及其下級(jí)多個(gè) View,合起來(lái)視作一個(gè) FB(Functionarity Block),在同一 Functionarity Block Namespace 下用 javascript 定義各節(jié)點(diǎn)行為。把相關(guān)節(jié)點(diǎn)的投影定義寫一起,很大程度消除了節(jié)點(diǎn)間隔閡,因?yàn)?,你能隨時(shí)可以定義一個(gè)變量用來(lái)傳數(shù)據(jù)。
2. 正交框架分析模式接本文上篇的例子,假定我們?cè)谠δ芑A(chǔ)上,再增加 “全局配置” 的功能,提供 3 個(gè)可選項(xiàng):“自動(dòng)選 Celsius 還是 Fahrenheit 格式”、“固定用 Celsius”、“固定用 Fahrenheit”。其中,第一個(gè)選項(xiàng) Auto(自動(dòng)選格式)依據(jù)瀏覽器特性推斷國(guó)別信息,然后智能選擇 Celsius 或 Fahrenheit。
新增如下界面設(shè)計(jì):
相應(yīng)的,增加一個(gè) Functionarity Block,JS 編碼如下:
(function() { // functionarity block var configComp = null; idSetter["config"] = function(value,oldValue) { // ... }; })();
該 FB 的入口節(jié)點(diǎn)是 configComp。再接著細(xì)化設(shè)計(jì),我們?cè)搶?configComp 定義挪到全局變量定義區(qū),因?yàn)樵摴?jié)點(diǎn)在兩個(gè) FB 功能塊都用到。
為方便講述起見(jiàn),我們把這兩個(gè) FB 分別稱為 config 與 calculator,以 FB 分布為橫軸,以 W 樹為縱軸,W 樹中的節(jié)點(diǎn)是層層串聯(lián)的,繪制這兩個(gè) FB 的分布如下圖:
當(dāng)我們整體設(shè)計(jì) GUI 時(shí),應(yīng)以 MVVM 方式思考。結(jié)合本例,也就是規(guī)劃 config 與 calculator 兩個(gè) “功能塊”,確定各功能塊的入口節(jié)點(diǎn),以及它的上下層串接關(guān)系。而處理各個(gè)功能塊之間聯(lián)動(dòng)關(guān)系時(shí),應(yīng)切換到 Flux 單向數(shù)據(jù)流思考方式。
總結(jié)一下,整個(gè) HTML 頁(yè)面是一顆 DOM 樹,是縱向的,在這顆樹劃分若干功能塊的過(guò)程,是基于 MVVM 為主的設(shè)計(jì)過(guò)程;而處理各功能塊之間橫向聯(lián)系,則以 FRP 思路為主導(dǎo)。這一縱一橫的思考方式,我們稱為 “正交框架” 分析模式。
說(shuō)明,F(xiàn)lux 是 FRP(Functional Reactiv Programming)開(kāi)發(fā)思想的一種實(shí)現(xiàn),對(duì)于 React 開(kāi)發(fā),上面所提 Flux 與 FRP 基本等效。
至于 FB 之間的功能如何交互,如果處理邏輯簡(jiǎn)單,不妨在相關(guān) FB 代碼塊中直接寫代碼,如果邏輯復(fù)雜,不妨取相關(guān) FB 的共有父節(jié)點(diǎn)作為入口節(jié)點(diǎn),新設(shè)一個(gè) FB 功能塊。取共有父節(jié)點(diǎn)的主要作用是,該父節(jié)點(diǎn)從創(chuàng)建到 unmount,可以覆蓋其下所有節(jié)點(diǎn)的生存周期,在它的 idSetter 函數(shù)中編程會(huì)方便一些。
3. 掛載數(shù)據(jù)來(lái)驅(qū)動(dòng)調(diào)測(cè)在可視設(shè)計(jì)器中開(kāi)發(fā)界面的過(guò)程,可能存在破壞式重構(gòu),比如你在某個(gè) FB 的入口節(jié)點(diǎn)指定 data 屬性值,然后它的子節(jié)點(diǎn)根據(jù) data 取值自動(dòng)生成子節(jié)點(diǎn),如果你給定的 data 初始值格式不對(duì),其下子節(jié)點(diǎn)會(huì)無(wú)法生成。所給初值不對(duì)可能因?yàn)樵O(shè)計(jì)變化了,你的 data 格式還沒(méi)來(lái)得及調(diào)整。
為了最大幅度減少上述破壞式重構(gòu)帶來(lái)錯(cuò)誤,在設(shè)計(jì)界面時(shí),我們建議用作驅(qū)動(dòng)源頭的數(shù)據(jù)初值應(yīng)取 “空” 值,比如賦給 null 或 [] 之類的值。
界面設(shè)計(jì)過(guò)程中,若想查看不同數(shù)據(jù)初值會(huì)驅(qū)動(dòng)什么樣的界面形態(tài),不妨啟用 W.$dataSrc 定義,比如前面例子界面缺省顯示 Celsius 溫度格式,因?yàn)?".body.calculator.field" 節(jié)點(diǎn)的 scale 屬性初值是 "c",現(xiàn)在我們想檢查 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" },用來(lái)預(yù)定義哪個(gè)節(jié)點(diǎn)要附加哪些屬性的初值。
上面代碼可以寫入獨(dú)立的 js 文件,多個(gè)此類 js 文件可構(gòu)造不同的調(diào)測(cè)場(chǎng)景,然后用 標(biāo)簽按需把某一個(gè) js 文件導(dǎo)入到被測(cè)頁(yè)面。
4. 結(jié)合 shadow-bootstrap 的可視化設(shè)計(jì)shadow-bootstrap 新近推出 v1.1 版本,Bootstrap 設(shè)計(jì)方式在 Shadow Widget 體系得到完整支持了。
Bootstrap 提供了優(yōu)秀的前端控件庫(kù),在 shadow-widget 上用 bootstrap 堪稱完美,畢竟上百個(gè) class 類誰(shuí)都記不住,大家做開(kāi)發(fā)時(shí),要不停的查手冊(cè)。用 shadow-widget 的可視化設(shè)計(jì)器,只需從右側(cè)樣板頁(yè)拖一個(gè)樣板扔進(jìn)來(lái),就創(chuàng)建你想要的構(gòu)件了,然后選擇相應(yīng)節(jié)點(diǎn),把相關(guān)屬性配置一下,你的界面很快就做好。
上圖是其中一個(gè)樣板頁(yè),該拖入哪個(gè)樣板,看一眼就能區(qū)分,不再受那么多 class 類名困擾了。
5. 注意事項(xiàng)剛開(kāi)始使用 Shadow Widget 時(shí),大家可能不適應(yīng)它的可視化設(shè)計(jì),容易忘掉幾項(xiàng)設(shè)計(jì)約束,簡(jiǎn)單舉幾個(gè)例子:
在根節(jié)點(diǎn)(即 ".body" 節(jié)點(diǎn))下只能擺放面板與絕對(duì)定位的構(gòu)件(如 ScenePage 等),即首層節(jié)點(diǎn)要么是 Panel 類構(gòu)件,要么是指定 position="absolute" 的非行內(nèi)構(gòu)件。
絕對(duì)定位的構(gòu)件,應(yīng)掛到根節(jié)點(diǎn),不宜在其它地方出現(xiàn)。(注:此項(xiàng)為建議,不強(qiáng)制)
面板之下不能直接放行內(nèi)構(gòu)件,要在面板下放置 P 類構(gòu)件后,才能放 Span 類構(gòu)件。
一個(gè)構(gòu)件要么啟用 "html." 屬性,要么使用它的若干子節(jié)點(diǎn),兩者只能二選一,若定義子節(jié)點(diǎn)了,以 "html." 表示文本將被忽略。
總之,與界面設(shè)計(jì)打交道,設(shè)計(jì)總是具體的,你要面對(duì)各類封裝好的構(gòu)件,不少構(gòu)件有特殊要求,《Shadow Widget 用戶手冊(cè)》有全面介紹,有必要通讀該手冊(cè)。
6. 關(guān)于團(tuán)隊(duì)分工Shadow Widget 最佳實(shí)踐還建議團(tuán)隊(duì)成員要按技能分工,至少有兩個(gè)工種,其一是能運(yùn)用他人已封裝好的 WTC 類或庫(kù)化 UI,進(jìn)行 GUI 開(kāi)發(fā);其二是為他人封裝 WTC 類或庫(kù)化 UI。前者對(duì)技能要求不高,后者則要求深入掌握 React 與 Shadow Widget 知識(shí)。
對(duì)于微型團(tuán)隊(duì),也應(yīng)按上述分工的思路規(guī)劃您的產(chǎn)品開(kāi)發(fā),因?yàn)檫@兩種分工的目標(biāo)不同,前者著眼短期目標(biāo),盡快把產(chǎn)品做出來(lái),把界面弄漂亮些,后者著眼中長(zhǎng)期目標(biāo),用封裝庫(kù)提高開(kāi)發(fā)復(fù)用率。即使是單人團(tuán)隊(duì),同樣需要分工,無(wú)非在時(shí)間上錯(cuò)開(kāi),一段時(shí)間承擔(dān)一種角色,另一段時(shí)間換一個(gè)角色。
Shadow Widget 當(dāng)前的 WTC 類與界面庫(kù)還不夠豐富,但它的架子已搭好,起點(diǎn)不低。它的定制擴(kuò)展能力出色,已通過(guò)一些上規(guī)模代碼的產(chǎn)品檢驗(yàn),如 shadow-bootstrap, pinp-blogs 等,具備一定成熟度。我們有理由相信,這個(gè)產(chǎn)品會(huì)隨著擴(kuò)展庫(kù)逐漸增多,前景越來(lái)越光明。
(本文完)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/89014.html
摘要:上例的功能塊定義了如下節(jié)點(diǎn)樹入口節(jié)點(diǎn)是面板,結(jié)合該節(jié)點(diǎn)的函數(shù)書寫特點(diǎn),我們接著介紹最佳實(shí)踐如何處理功能塊之內(nèi)的編程。 本文介紹 React + Shadow Widget 應(yīng)用于通用 GUI 開(kāi)發(fā)的最佳實(shí)踐,只聚焦于典型場(chǎng)景下最優(yōu)開(kāi)發(fā)方法。分上、下兩篇講解,上篇概述最佳實(shí)踐,介紹功能塊劃分。 showImg(https://segmentfault.com/img/bVWu3d?w=6...
摘要:前言非正經(jīng)入門是相對(duì)正經(jīng)入門而言的。不過(guò)不要緊,正式學(xué)習(xí)仍需回到正經(jīng)入門的方式。快速入門建議先學(xué)會(huì)用拼文寫文檔注冊(cè)一個(gè)賬號(hào),把庫(kù)到自己名下,然后用這個(gè)庫(kù)寫自己的博客,參見(jiàn)這份介紹。會(huì)用拼文寫文章,相當(dāng)于開(kāi)發(fā)已入門三分之一了。 本系列博文從 Shadow Widget 作者的視角,解釋該框架的設(shè)計(jì)要點(diǎn),既作為用戶手冊(cè)的補(bǔ)充,也從更本質(zhì)角度幫助大家理解 Shadow Widget 為什么這...
摘要:是前端開(kāi)發(fā)領(lǐng)域新興的方法論體系,它繼承了與編程理念,在技術(shù)上有不少創(chuàng)新。但專利與開(kāi)源協(xié)議是平行的兩個(gè)世界,改底層也不大容易解決問(wèn)題。此外,要求在中結(jié)合各屬性的是否變化,判斷是否該觸發(fā)更新。 ReRest (Reactive Resource State Transfer) 是前端開(kāi)發(fā)領(lǐng)域新興的方法論體系,它繼承了 MVVM 與 FRP 編程理念,在技術(shù)上有不少創(chuàng)新。本文從專利稿修改而來(lái)...
閱讀 3268·2023-04-25 22:47
閱讀 3779·2021-10-11 10:59
閱讀 2314·2021-09-07 10:12
閱讀 4269·2021-08-11 11:15
閱讀 3440·2019-08-30 13:15
閱讀 1757·2019-08-30 13:00
閱讀 976·2019-08-29 14:02
閱讀 1691·2019-08-26 13:57