国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

React 可視化開發(fā)工具 shadow-widget 最佳實踐(上)

techstay / 1843人閱讀

摘要:上例的功能塊定義了如下節(jié)點樹入口節(jié)點是面板,結(jié)合該節(jié)點的函數(shù)書寫特點,我們接著介紹最佳實踐如何處理功能塊之內(nèi)的編程。

本文介紹 "React + Shadow Widget" 應(yīng)用于通用 GUI 開發(fā)的最佳實踐,只聚焦于典型場景下最優(yōu)開發(fā)方法。分上、下兩篇講解,上篇概述最佳實踐,介紹功能塊劃分。

1. 最佳實踐概述

按遵循 ES5 與 ES6+ 區(qū)分,Shadow Widget 支持兩種開發(fā)方式,一是用 ES5 做開發(fā),二是搭建 Babel 轉(zhuǎn)譯環(huán)境用 ES6+ 做開發(fā),之所以劃分兩大類,因為它們之間差別不僅僅是 javascript 代碼轉(zhuǎn)譯,而是涉及在哪個層面定義 React Class,進而與源碼在上層還是下層維護,以及與他人如何協(xié)作等相關(guān)。

如本系列博客《shadow-widget 的非可視開發(fā)方法》一文介紹,用 ES5 定義 React class 的方式是:

var MyButton = T.Button._createClass( {
  getDefaultProps: function() {
    var props = T.Button.getDefaultProps();
    // props.attr = value;
    return props;
  },
  
  getInitialState: function() {
    var state = this._getInitialState(this);
    // ...
    return state;
  }
  
  $onClick: function(event) {
    alert("clicked");
  }
});

而用 ES6+ 開發(fā),這么定義 React class:

class MyButton_ extends T.Button_ {
  constructor(name,desc) {
    super(name,desc);
  }
  
  getDefaultProps() {
    var props = super.getDefaultProps();
    // props.attr = value;
    return props;
  }
  
  getInitialState() {
    var state = super.getInitialState();
    // ...
    return state;
  }

  $onClick: function(event) {
    alert("clicked");
  }
}

var AbstractButton = new MyButton_();  // MyButton_ is WTC
var MyButton = AbstractButton._createClass(); // MyButton is React class

由于 ES6+ 語法能兼容 ES5,所以,即使采用 ES6+ 開發(fā)方式,前一種 ES5 的 React class 定義方法仍然適用。但,自定義擴展一個 WTC 類必須用 ES6+,就象上面 "class MyButton_ extends T.Button_" 語法,只能在 ES6+ 下書寫。

考慮到用 ES5 編程不必搭建 Babel 開發(fā)環(huán)境,ES5 能被 ES6+ 兼容,向 ES6+ 遷移只是整體平移,不必改源碼。加上 Shadow Widget 及第 3 方類庫,已提供夠用的基礎(chǔ) WTC 類(這意味著我們并不迫切依賴于用 ES6+ 擴展 WTC),所以,我們將 Shadow Widget 最佳實踐確定為:用 ES5 實施主體開發(fā)

Shadow Widget 最佳開發(fā)實踐的大致操作過程如下:

創(chuàng)建一個新的工程,參見《Shadow Widget 用戶手冊》(下面簡稱《手冊》)中 “5.1.1 創(chuàng)建工程” 一節(jié)
應(yīng)選擇一個合適的 "網(wǎng)頁樣板" 來創(chuàng)建,Shadow Widget 是一個可繼承重用的 lib 庫體系,最基礎(chǔ)的是 shadow-widget 庫自身,其上還有 shadow-slidepinp-blogs 等擴展庫,各個擴展項目一般會提供它本層的網(wǎng)頁樣板(通常放在 /output/shared/pages/ 目錄下)。

在創(chuàng)建的網(wǎng)頁文件追加 代碼
然后在 your_file.js 文件編寫 ES5 代碼。

使用 Shadow Widget 的可視設(shè)計器設(shè)計用戶界面
用戶界面設(shè)計的結(jié)果以轉(zhuǎn)義標簽的形式,保存在你的 "*.html" 網(wǎng)頁文件中,然后你可以在 your_file.js 同步編寫 JS 代碼。

完成開發(fā)與測試后,把相關(guān)的 html, js, css 等文件上傳發(fā)布到服務(wù)器發(fā)布
因為不必做 ES6 轉(zhuǎn)譯,發(fā)布操作很直接。或許您要調(diào)整 js, css, png 等文件位置,或許您需 minify 某個 JS 文件,這些都是前端開發(fā)的基本技能,不是 Shadow Widget 特有的。

最佳實踐還建議多用 idSetter 函數(shù)定義各 component 的行為,不用(或少用)在 main[path] 定義投影類的方式,因為 idSetter 的函數(shù)式風格,讓 MVVM 與 Flux 兩種框架的交匯點處理起來更便利。

接下來,在展開細節(jié)介紹之前,我們先梳理一下 Shadow Widget 技術(shù)體系的幾個特色概念。

2. p-statev-state

p-statev-state 是 uglee 在 《少婦白潔系列之 React StateUp Pattern, Explained》 一文提出的概念,我們借用過來解釋 React 中的數(shù)據(jù)流轉(zhuǎn)模式。p-statepersistent state,是生命周期超過組件本身的 state 數(shù)據(jù),即使組件從 DOM 上銷毀,這些數(shù)據(jù)仍然需要在組件外部持久化。v-statevolatile state,是生命周期和組件一樣的 state 數(shù)據(jù),如果組件從 DOM 上銷毀,這些 state 將一起銷毀。

結(jié)合 Flux 框架,v-state 就是 comp.props.xxxcomp.state.xxx 數(shù)據(jù),p-state 就是 store 里的數(shù)據(jù),這么說雖有失嚴謹,但大致如此。如果未使用 Flux 框架,對 comprender() 過程產(chǎn)生影響的所有數(shù)據(jù)中,全局變量或其它節(jié)點(包括上級節(jié)點)中的屬性,都算當前節(jié)點的 p-state

不過,v-statep-state 劃分是靜態(tài)的,相對而言的。比如,初始設(shè)計界面只要求顯示攝氏度(Celsius)格式的溫度值,然后覺得要適應(yīng)全球化應(yīng)用,攝氏度與華氏度(Fahrenheit)都得顯示,再往后發(fā)現(xiàn),Celsius 與 Fahrenheit 并列顯示不夠友好,就改成動態(tài)可配置,取國別信息后自動設(shè)成兩者中一個。這種設(shè)計變遷中,“當前溫度格式” 與 “并列顯示或只顯示一種” 的配置數(shù)據(jù)經(jīng)常在 v-statep-state 之間變遷。

React 工具鏈上幾個 Flux 框架主要區(qū)別在于,如何定位與使用 p-state,它們對 v-state 使用基本一致,我們拿 reflux、redux、shadow-widget 三者分別舉例。

Reflux 采用多 store,其 store 設(shè)計與 component 很接近,可以這么簡單理解:既然跨 Component 存在數(shù)據(jù)交互,父子關(guān)系可以用 props 傳遞,非父子關(guān)系傳不了,怎么辦呢?那就設(shè)立第三方實體(也就是 store)處理此事。Redux 采用單 store,把它理解成一大坨全局變量就好,它以 action 設(shè)計為提綱,圍繞 action 組織 reducer 函數(shù),而 Reflux 中提綱挈領(lǐng)的東西則是 store 中的數(shù)據(jù),圍繞數(shù)據(jù)組織 action 定義。若對比這兩者,Reflux 方式更易理解,需求分解與設(shè)計展開過程更人性化,不過,Reflux 沒有突破 React 固有限制,因為多 store 模式,實踐中大家經(jīng)常很糾結(jié)某項數(shù)據(jù)該放在 component 中,還是放在 store 中呢?如前所述,一項數(shù)據(jù)是否為 v-state 是相對的,產(chǎn)品功能疊代后,數(shù)據(jù)經(jīng)常要從 v-state 提升到 p-state,或者,若原設(shè)計偏于寬泛,還需將 p-state 降回 v-state。Reflux 困境在于 Store 設(shè)計與 Component 不對稱,順應(yīng)來回變遷的成本較高。

Shadow Widget 也是多 Store,Component 自身就是 store,這克服了 Reflux 主要不足。另外結(jié)合 MVVM 架構(gòu)的可視化特點,Shadow Widget 還克服了 redux 主要不足。

3. 幾種 Lift State Up 方式

Shadow Widget 介紹了一種 “逆向同步 & 單向依賴” 的機制,在如下節(jié)點樹中,nodeE 要使用 nodeC 中的數(shù)據(jù),但 nodeC 生存周期與 nodeE 并不一致,所以,引入一種機制,在它們共同的父節(jié)點 nodeA 設(shè)置一個屬性(比如 attrX),nodeC 中的該數(shù)據(jù)能自動同步到 nodeA 中,然后讓 nodeE 只依賴 nodeA 中的數(shù)據(jù)(比如 attrX),只要 NodeE 還存活,父節(jié)點 nodeD 與 nodeA 必然存活。

  nodeA
  +-- nodeB
  |   +-- nodeC
  +-- nodeD
  |   +-- nodeE

React 官方介紹了一種 "Lifting State Up" 方法,借助函數(shù)式編程的特點,把控制界面顯示效果的變量,從子節(jié)點提升到父節(jié)點,子節(jié)點的事件函數(shù)改在父節(jié)點定義,就達到 Lift State Up 的效果。

既然提升 state 能突破 React 對數(shù)據(jù)傳遞的限制,那么,極端一點,能否把所有用到的數(shù)據(jù)都改成全局變量呢?答案當然可以,不過缺少意義,這么做,無非將分散在各節(jié)點的邏輯,轉(zhuǎn)移到處理一堆全局變量而己,設(shè)計過程本該分解,而非合并。可視節(jié)點分層分布本是天然的功能劃分方式,放棄它改換門庭無疑把事情搞復雜了,可惡的 Redux 就是這么干的。

從本質(zhì)上看,Redux 把 state 數(shù)據(jù)全局化了(成為單 store),但它又以 action 主導切割數(shù)據(jù),你并不能直接存取全局 store,而是改由 action 驅(qū)動各個 reducer,各 reducer 只孤立處理它自身可見的 state。由此我有兩點推論:

棄用界面現(xiàn)成的分解方式,改建另一套體系并不明智
就像描述雙人博擊,最直接的方式是先區(qū)分場上誰是誰,誰出擊,誰防守,出擊者揮拳,防守者縮頭躲避。Redux 行事風格是先設(shè)計 “揮拳”、“縮頭” 之類的 action,然后分解實施這些 action,來驅(qū)動各種 state 變化。該模式之所以行得通,不是 Redux 有多好,而是人腦太奇妙,編程中除了腦補產(chǎn)品應(yīng)用場景,偶爾還會插幀處理俊男靚女圖片 :)

數(shù)據(jù)隔離是必需的,否則無法應(yīng)對大規(guī)模產(chǎn)品開發(fā)
后文我們將介紹最佳實踐中的數(shù)據(jù)隔離方法,以功能場景為依據(jù)。

4. 功能塊

為方便說明問題,我們?nèi)?React 官方 "Lifting State Up" 一文介紹的,判斷溫度是否達到沸點的應(yīng)用場景,編寫一段樣例代碼。

我們想設(shè)計如下界面:

4.1 樣例程序的功能

如果輸入溫度未超沸點,界面顯示 "The water would not boil",若超沸點則顯示 "would boil"。另外,用于輸入溫度的方框(即后述的 field 節(jié)點)要求可配置,用 scale="c" 指示以攝氏度表示,標題提示 "Temperature in Celsius",否則 scal="f" 指示華氏度,提示 "in Fahrenheit"

我們在 Shadow Widget 可視設(shè)計器中完成設(shè)計,存盤后生成的轉(zhuǎn)義標簽如下:

legend

然后在 JS 文件編寫如下代碼:

if (!window.W) { window.W = new Array(); W.$modules = [];}
W.$modules.push( function(require,module,exports) {

var React = require("react");
var ReactDOM = require("react-dom");
var W = require("shadow-widget");

var main = W.$main, utils = W.$utils, ex = W.$ex;
var idSetter = W.$idSetter;

if (W.__design__) return;

(function() { // functionarity block

var selfComp = null, verdictComp = null;
var scaleNames = { c:"Celsius", f:"Fahrenheit" };

idSetter["calculator"] = function(value,oldValue) {
  if (value <= 2) {
    if (value == 1) {      // init
      selfComp = this;
      this.defineDual("temperature", function(value,oldValue) {
        if (Array.isArray(value) && verdictComp) {
          var scale = value[0], degree = value[1];
          var isBoil = degree >= (scale == "c"?100:212);
          verdictComp.duals["html."] = isBoil?
            "The water would boil.":
            "The water would not boil.";
        }
      });
    }
    else if (value == 2) { // mount
      verdictComp = this.componentOf("verdict");
      
      var field = this.componentOf("field");
      var inputComp = field.componentOf("input");
      var legend = field.componentOf("legend");
      var sScale = field.props.scale || "c";
      legend.duals["html."] = "Temperature in " + scaleNames[sScale];
      
      inputComp.listen("value",onInputChange.bind(inputComp));
      this.duals.temperature = [ sScale,
        parseFloat(inputComp.duals.value) || 0
      ];
    }
    else if (value == 0) { // unmount
      selfComp = verdictComp = null;
    }
    return;
  }
  
  function onInputChange(value,oldValue) {
    var scale = this.parentOf().props.scale || "c";  // "c" or "f"
    var degree = parseFloat(value) || 0; // take NaN as 0
    selfComp.duals.temperature = [scale,degree];
  }
};

})();

});

上面 if (W.__design__) return 一句,讓其后代碼在 __design__ 態(tài)時(即,在可視設(shè)計器中)不生效。

4.2 功能塊

按我們最佳實踐的做法,界面可視化設(shè)計的結(jié)果保存在頁面 *.html 文件,而界面的代碼實現(xiàn)(包括定義事件響應(yīng)、綁捆數(shù)據(jù)驅(qū)動等)在 JS 文件編寫。所以,上面例子的設(shè)計結(jié)果包括兩部分:*.html 文件中的轉(zhuǎn)義標簽與 *.js 文件中的 javascript 腳本。

多個組件共同完成某項特定功能,他們合起來形成邏輯上的整體叫做 “功能塊” (Functionarity Block)。典型的 JS 文件通常按這個樣式編寫:

if (!window.W) { window.W = new Array(); W.$modules = [];}
W.$modules.push( function(require,module,exports) {

// 全局變量定義
var React = require("react");
var ReactDOM = require("react-dom");
var W = require("shadow-widget");

var main = W.$main, utils = W.$utils, ex = W.$ex;
var idSetter = W.$idSetter;

if (W.__design__) return;

// 功能塊定義
(function() {

// ....

})()

// 初始化定義
main.$onLoad.push( function() {
  // ...
});

});

頭部用來定義若干全局變量,然后定義功能塊,功能塊可能有多個,上面舉例的判斷溫度是否超沸點,比較簡單,定義一個功能塊就夠了,最后定義 main.$onLoad 全局初始化函數(shù)。

之所以將一個功能塊用一個函數(shù)包裹,主要為了構(gòu)造獨立的命名空間(Namespace),比如前面舉例的代碼:

(function() { // functionarity block

var selfComp = null, verdictComp = null;
var scaleNames = { c:"Celsius", f:"Fahrenheit" };

idSetter["calculator"] = function(value,oldValue) {
  // ...
};

})();

由功能塊函數(shù)構(gòu)造的 Namespace 也稱 “功能塊空間”(Functionarity Block Space),在功能塊內(nèi)共享的變量在此定義,比如這里的 selfComp, verdictComp, scaleNames 變量。

4.3 功能塊入口節(jié)點

一個功能塊的入口節(jié)點是特殊節(jié)點,它的生存周期反映了功能塊的生存周期。它的各層子節(jié)點若還存在(即在 unmount 之前),入口節(jié)點必然存在。因為入口節(jié)點的生存期能完整覆蓋它各級子節(jié)點的生存期,所以,我們一般在入口節(jié)點定義 idSetter 函數(shù),承擔本功能塊的主體邏輯處理。

上例的功能塊定義了如下節(jié)點樹:

 Panel (key=calculator)
  +-- Fieldset (key=field)
  |   +-- Legend (key=legend)
  |   +-- Input (key=input)
  +-- P (key=verdict)

入口節(jié)點是 calculator 面板,結(jié)合該節(jié)點的 idSetter 函數(shù)書寫特點,我們接著介紹 Shadow Widget 最佳實踐如何處理 "功能塊" 之內(nèi)的編程。

?

1) 為方便編程,不妨在 “功能塊空間” 多定義變量

因為 “功能塊空間” 的變量不外泄到其它功能塊,我們不必擔心多定義變量會給其它部分編碼帶來 Side Effects。功能塊里各個節(jié)點,只要不是動態(tài)創(chuàng)建、刪除、再創(chuàng)建那種,都可定義成 “功能塊空間” 的變量,我們一般在入口節(jié)點 idSetter 函數(shù)的 unmount 代碼段(即 if (value == 0)),把各個節(jié)點的變量置回 null 值。

對于動態(tài)增刪的節(jié)點,不妨用 this.componentOf(sPath) 動態(tài)方式定位。

?

2) 功能塊內(nèi)的數(shù)據(jù)主體流向,宜在界面設(shè)計時就指定

在功能塊的 idSetter 函數(shù)也能以編程方式設(shè)計節(jié)點間數(shù)據(jù)流向,考慮到界面設(shè)計與數(shù)據(jù)流規(guī)則直接相關(guān),能以描述方式(轉(zhuǎn)義標簽形式)表達數(shù)據(jù)流的,盡量用描述方式,不方便的才用 JS 編程方式去實現(xiàn)。因為,一方面,Shadow Widget 的指令式 UI 描述能力夠強,另一方面,這么做有助于讓 MVVM 中的 ViewModel 集中,從而降低設(shè)計復雜度。

界面設(shè)計時,不妨多用下述技巧:

$for=""$$for="" 開啟一層 callspace,方便其下節(jié)點的可計算屬性用 duals.attr 引用數(shù)據(jù)。

善用 $trigger 同步數(shù)據(jù)

如果節(jié)點層次復雜,不妨采用導航面板(NavPanelNavDiv),用 "./xx.xx" 相對路徑方式讓節(jié)點定位更方便

?

3) 善用變量共享機制

若按 React 原始開發(fā)方式編碼,不借助任何 Flux 框架工具,大家肯定覺得編程很不方便,因為各節(jié)點除了能往子節(jié)點單向傳遞 props 外,與其它節(jié)點的交互幾乎隔了一道黑幕。然而,不幸的是,React 幾個主流的 Flux 工具,均沒有妥善解決幾個主要問題,上面提到的 Reflux、Redux 均如此,React 官方的 react-flux 更難用。

相對而言,Shadow Widget 的解決方案好很多,一方面,在 Component 節(jié)點引入 “雙源屬性”,功能強大,能讓基于過程組裝的 UI 渲染,過渡到 以屬性變化來驅(qū)動渲染,即:除了 “功能塊” 的入口節(jié)點需集中編寫控制邏輯,其它節(jié)點的編程,基本簡化為定制若干 duals 函數(shù)(用 defineDual() 注冊)。另一方面,Shadow Widget 借助 Functionarity Block 抽象層來重組數(shù)據(jù),以功能遠近作聚合依據(jù),明顯比以 Action 驅(qū)動的 Reducer 分割要高明。

從本質(zhì)上講,拎取 “功能塊抽象層” 也是 Lift State Up 的一種手段,限制更少,結(jié)合于 JS 編程也更自然。虛擬 DOM 樹中的各 component 節(jié)點有隔離措拖,不能互相識別,但函數(shù)編程沒什么限制,比如上面例子,selfComp = this 把一個 Component 賦給 “功能塊空間” 的變量 selfComp 后,同在一個功能塊的其它函數(shù)都能使用它了。

(未完,下篇待續(xù)...)

?

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/89010.html

相關(guān)文章

  • React 可視開發(fā)工具 shadow-widget 最佳實踐(下)

    摘要:本文介紹應(yīng)用于通用開發(fā)的最佳實踐,只聚焦于典型場景下最優(yōu)開發(fā)方法。結(jié)合的可視化設(shè)計新近推出版本,設(shè)計方式在體系得到完整支持了。注此項為建議,不強制面板之下不能直接放行內(nèi)構(gòu)件,要在面板下放置類構(gòu)件后,才能放類構(gòu)件。 本文介紹 React + Shadow Widget 應(yīng)用于通用 GUI 開發(fā)的最佳實踐,只聚焦于典型場景下最優(yōu)開發(fā)方法。分上、下兩篇講解,下篇講述正交框架分析模式與常用調(diào)測...

    wenshi11019 評論0 收藏0
  • React 可視開發(fā)工具 Shadow Widget 非正經(jīng)入門(之一:React 三宗罪)

    摘要:前言非正經(jīng)入門是相對正經(jīng)入門而言的。不過不要緊,正式學習仍需回到正經(jīng)入門的方式。快速入門建議先學會用拼文寫文檔注冊一個賬號,把庫到自己名下,然后用這個庫寫自己的博客,參見這份介紹。會用拼文寫文章,相當于開發(fā)已入門三分之一了。 本系列博文從 Shadow Widget 作者的視角,解釋該框架的設(shè)計要點,既作為用戶手冊的補充,也從更本質(zhì)角度幫助大家理解 Shadow Widget 為什么這...

    dongxiawu 評論0 收藏0
  • 重磅:前端 MVVM 與 FRP 的升階實踐 —— ReRest 可視編程

    摘要:是前端開發(fā)領(lǐng)域新興的方法論體系,它繼承了與編程理念,在技術(shù)上有不少創(chuàng)新。但專利與開源協(xié)議是平行的兩個世界,改底層也不大容易解決問題。此外,要求在中結(jié)合各屬性的是否變化,判斷是否該觸發(fā)更新。 ReRest (Reactive Resource State Transfer) 是前端開發(fā)領(lǐng)域新興的方法論體系,它繼承了 MVVM 與 FRP 編程理念,在技術(shù)上有不少創(chuàng)新。本文從專利稿修改而來...

    Cciradih 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<