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

資訊專欄INFORMATION COLUMN

React 可視化開發(fā)工具 shadow-widget 的非可視開發(fā)方法

icyfire / 1328人閱讀

摘要:提倡在可視設計器中開發(fā)用戶界面,輸出轉義標簽,而非。被官方忽視的開發(fā)方法區(qū)別于其它前端框架的關鍵特色是可視化設計,因為與混寫,不能直接支持可視化設計。最終返回的是,還是,或是其它是動態(tài)變化的。官方為此提供一種上舉的解決方案,參見。

Shadow Widget 提倡在可視設計器中開發(fā)用戶界面,輸出轉義標簽,而非 JSX。許多童鞋可能不知道 SW 同樣支持用 JSX 設計界面,開發(fā)體驗比原生 React 編程好出很多,本文就介紹這方面知識。

?

1. 被官方忽視的開發(fā)方法

Shadow Widget 區(qū)別于其它前端框架的關鍵特色是可視化設計,因為 JSX 與 javascript 混寫,不能直接支持可視化設計。所以,SW 用 “轉義標簽” 表達可視設計的輸出,因為 SW 強調可視化,所以如何運用 JSX 的內容,在官方文檔中被弱化了,有一些零星介紹,分散在手冊各個章節(jié),本文將它們串接起來講。

在 Shadow Widget 下做開發(fā),既可以是主流的 “正交框架” 模式(也就是遵循 MVVM 思路設計可視界面,再用 Flux 框架組織橫向數據流的開發(fā)方式),也可以完全順從 React 原生模式,只把 SW 看作更好的 lib 庫來使用。**下面我們結合代碼實例,講解后一開發(fā)方式。

由于 JSX 界面設計與用鼠標拖拉配置界面的設計是等價的,我們以 React 原生模式做開發(fā),相對 SW 主流方式,主要損失可視化的直觀特性,其它并不損失。當然,目前使用 JSX 還得借助 Babel 轉譯環(huán)境,搭建 "Babel + Browserify" 或 "Babel + Webpack" 開發(fā)環(huán)境是不得已的選擇。

如何創(chuàng)建新工程及如何搭建 Browerify 或 Webpack 環(huán)境,請參考《Shadow Widget 用戶手冊》的 “3.1 搭建工程環(huán)境” 一章。

2. 幾個等價概念

1) json-x

json-x 是 “轉義標簽” 的數據化形式,用 javascript 的 Array 數據表達各層嵌套節(jié)點。json-x 與轉義標簽的關系,就像 xml 與 HTML DOM 的關系。json-xJSX 是對應的,是同一類東西,不過 json-x 不如 JSX 易讀。

?

2) WTC(Widget Template Class,構件模板類)

WTC 對應于 React 中各 Component 的 class 類定義。React 要求這么定義:

class MyButton extends React.Component {
  constructor(props) {
    // ...
  }
  
  componentDidMount() {
    // ...
  }

  render() {
    // ...
  }
}

WTC 要求這么定義(必須從已有的 WTC 類繼承,而且只能用 ES6+ 語法才做得到):

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;
  }

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

WTC 不是 React class,不能在 JSX 中直接使用,應先轉成 React class。

?

3) render 函數

如果想把 React 程序寫得更嚴謹,減少 Side Effects,應該在 render() 函數集中處理各種控制邏輯,對其它函數的功能,諸如 getInitialState, componentDidMount, componentWillUnmount 等,不妨簡單這么理解:為 render() 提供配置服務。當配置縮簡到可以忽略時,Component 定義便退化為單個函數(即 Functional Component),該函數等效提供 render 功能。

Shadow Widget 按這個思路,把控制邏輯集中在 render() 函數中處理,包括:duals 雙源屬性的偵聽、觸發(fā)、聯動,$if, $for 等控制指令與可計算屬性自動更新等。因為復雜性在此封裝,render 不便公開給用戶定制,另外,Shadow Widget 為了支持可視化設計,盡量將 render() 中的邏輯控制分解,分離出屬性項供配置,所以,Shadow Widget 不再鼓勵用戶自定義 render() 函數,雖然大家可以 hack 各 WTC 的 render 實現過程,然后仿照著自己寫一個,但這不是建議的做法。

借助以下途徑,在 Shadow Widget 可實現 render 過程的邏輯控制:

props.attr, duals.attr, state.attr 取值控制當前節(jié)點的界面表現
其中,props.attr 反映了 Component 生存周期內的不變量,duals.attr 是可變量,state.attr 也是可變量,傾向用作節(jié)點內私有控制(不供其它節(jié)點調用)。

在 render 渲染之外,調用 comp.setChild() 來增、刪、修改子節(jié)點
即:不在 render() 調用的過程之中調用 comp.setChild()

idSetter 函數中,調用 utils.setChildren() 來增、刪、修改子節(jié)點

上面 3 點,第一點比較好理解,第二點是 Shadow Widget 增加的,原生 React 不提供這種操作,比方說,在一個頁面提交一條反饋意見,用戶可以點一下 “刪除” 按鈕可刪掉剛提交的意見。若用原始 javascript 實現,大概用這么一條語句:

commentNode.parentNode.removeChild(commentNode);

原生 React 處理這種需求要稍微繞一下,給 commentNode 的父節(jié)點發(fā)個 "刪除指令",然后由它代為實施 "刪除操作"。Shadow Widget 提供 comp.setChild() 相當于補回 javascript 本可直接實現的操作。

上面第三點,在傳入的 props.id__ 函數中,可以通過修改 duals.attrstate.attr 改變本節(jié)點的顯示效果,還能通過調用 utils.setChildren() 來改變子節(jié)點怎么顯示。其實現原理與在 render() 函數中寫代碼是等價的,將在后文細述。

3. 將 WTC 轉化為 React class

同為定義 component 類,WTC 繼承鏈與 React class 繼承鏈是不相干的兩條鏈,前者起始于 T.Widget_,后者起始于 React.Component。當前者 WTC 類實例調用 _createClass() 得到值,才與后者等效。

比如:

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

var MyButton2 = AbstractButton._createClass( {
  $onClick: function(event) {
    alert("another onClick");
  }
});
var jsx2 = test2;

var MyButton3 = T.Button._createClass( {
  $onClick: function(event) {
    alert("yet another onClick");
  }
});
var jsx3 = test3;

簡單理解 WTC,可把它看作 React class 的 class 定義,即,它是一種用于生成 React class 的模板,所以 WTC 是 "構件模板" 的類(Widget Template Class)。

我們之所以要插入 “模板” 一級的抽像物,主要為了適應可視化編程,Widget Template 不只用來生成 React class,也為可視設計器提供支持。另外,一個 Component 的行為在 WTC 中定義,還是在 _createClass(defs) 的傳入參數(即投影類)定義是可選的,比如上例中 $onClick 事件函數,在哪個地方都可定義。這么設計的好處是:習慣用 ES6 編碼的童鞋,在 WTC 編程,習慣用 ES5 的,用投影類編程,不必搭建 Babel 轉譯環(huán)境。

Shadow Widget 提供 utils.getWTC() 接口用來批量從 T 模塊取得 React class,比如:

var t = utils.getWTC("*"); // or, utils.getWTC(["Panel","P"])

var jsx = ( 
  Hello, world!
  
 );

請注意,使用來源于 WTC 的 React class 構造界面,系統會自動生成一顆樹,各節(jié)點按層次串接起來,任何非 WTC 節(jié)點都不能成為 WTC 節(jié)點的父節(jié)點,反過來可以,即:非 WTC 節(jié)點能掛到 WTC 節(jié)點下,但 WTC 節(jié)點不能掛到非 WTC 節(jié)點下。比如上面 button 不是 WTC 節(jié)點,可以掛到 WTC 節(jié)點 t.P 之下,成為末梢節(jié)點。

4. 用函數封裝投影定義 4.1 從 SFC 到 PRC,再到 idSetter

React 有兩種純渲染函數,其一是 "Stateless Functional Component"(SFC),如下:

function HelloMessage(props) {
  return 
Hello {props.name}
; }

還有一種 "Pure Render Component"(PRC),所謂 pure 是指,如果 propsstate 不變,則 render 結果不變。比如:

import PureRender from "react-addons-pure-render-mixin";

class HelloComponent extends React.Component {
  constructor(props) {
    super(props);
    this.shouldComponentUpdate = PureRender.shouldComponentUpdate.bind(this);
  }
  
  render() {
    return 
Hello {this.props.name}
; } }

SFC 似乎簡單,易讀易維護,也方便 "Lifting State Up"(后文有論述),但 SFC 比 PRC 缺少用 shouldComponentUpdate() 避免重復刷新,性能會受影響,另外,JSX 中把 SFC 的函數用作 tag,動詞用作名詞,閃著一絲詭異的光。

Shadow Widget 開創(chuàng)性的設計 idSetter 機制,將 SFC 與 PRC 的優(yōu)點結合起來了。一方面,你不需要非得用 class 類定義一個 Component,在層層嵌套的函數式風格中,不宜隨便找個地方就定義 class,另外,idSetter 是函數,在一個函數中定義 Component 所有行為。

比如:

function btn__(value,oldValue) {
  if (value <= 2) {
    if (value == 1) {  // init process
    }
    else if (value == 2) { // mount
    }
    else if (value == 0) { // unmount
    }
    return;
  }

  // rendering for evey render()
  // ...
}

var jsx = test

若用 SFC 方式編程,先定義的一個 MakeButton 函數,然后用 test 描述 UI 界面。MakeButton() 最終返回的 tag 是 button,還是 span,或是其它是動態(tài)變化的。但這里 test 卻是明確指定 tag 是 MyButton,很直接。

設計界面時,手頭的 tag 標簽相當于食材(比如 “米飯”),給各 tag 指定各種屬性來控制它的外觀,這是最直接的設計方式。Stateless Functional Component 是 “紫菜包飯”,用函數形式包裹食材,idSetter 方式則相當于 “飯包紫菜包飯”,外觀表現仍是 “米飯”,內層用紫菜包裹過。

4.2 idSetter 優(yōu)點

傳遞給 $id__ 的函數是 idSetter,這是全能的,因為系統在基類的 componentWillMount, componentDidMount, componentWillUnmount, render 這 4 個函數中增加了對 idSetter 函數自動調用。其中,value <= 2 下的 3 個條件分支,分別等效于在 componentWillMount, componentDidMount, componentWillUnmount 中編碼,其它條件(即 value > 2)相當于在 render 函數中編碼。

這么處理有幾個好處:

增強了功能,又契合函數式編程風格
Functional Component 功能受限,因為不能插入 componentDidMount, componentWillUnmount 時的處理,若用 React class 定義一個 Component 的行為,你擁有 componentDidMount, componentWillUnmount 等專項處理函數,但 React class 定義是靜態(tài)聲明,非單項函數,把 class 定義在層層嵌套的任一函數中,比較別扭。idSetter 同時克服了這兩種缺陷。

便于 lifting state up
當我們采用 JSX 描述界面時,行為定義(屬性與動作函數)與虛擬 DOM 描述混在一起,這時僅依賴 props.attr 逐層傳遞的數據共享方式,用起來不方便。React 官方為此提供一種 “上舉 state” 的解決方案,參見 Lifting state up。

我們取 React 官方 Lifting State Up 一文介紹的,判斷溫度是否達到沸點的場景,舉個例子:

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, t = utils.getWTC("*");

function calculatorUI() {
  var selfComp = null, verdictComp = null;
  var scaleNames = { c:"Celsius", f:"Fahrenheit" };
  
  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];
  }
  
  function calculator__(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));
        selfComp.duals.temperature = [ sScale,
          parseFloat(inputComp.duals.value) || 0
        ];
      }
      else if (value == 0) { // unmount
        selfComp = verdictComp = null;
      }
      return;
    }
  }
  
  return ( 
    
      
      
    
    
   );
}

main.$onLoad.push( function() {
  var bodyComp = W.body.component;
  var jsx = calculatorUI();
  bodyComp.setChild(jsx);
});

在 Flux 框架中,由 Store 直接驅動的那個 View 也叫 Controller View,其下層由各層 View 由 Controller View 往下逐層傳數據來驅動。當 Store + Controller View 的處理邏輯越集中,可理解性就越好,編碼與維護也越容易。反過來,如果 Controller View 的下層節(jié)點還處理復雜的控制邏輯,你就不得不將它設計成 "Store + Controller View",程序復雜性無疑會增加。

Shadow Widget 的 "Lift State Up" 比 React 原生方式更好用。

1) 首先,Shadow Widget 有雙源屬性,更多過程處理轉為對 duals 屬性的讀寫,更簡單,更直接,比如上面 legend 節(jié)點,用 legend.duals["html."] = sDesc 直接改變界面文本,是外掛的,若在 render 函數中 return {sDesc} 則是過程處理,是內嵌的,不利于將子節(jié)點業(yè)務邏輯提升到父節(jié)點。

2) 其次,雙源屬性的 listen 機制,也有助于 "Lift State Up",比如上面 inputComp.listen("value",onInputChange),在 輸入框輸入文本將驅動 onInputChange 調用,有關響應函數能輕松 "Lift Up"。

3) 還有,idSetter 是函數,函數套函數很容易,很自然,如果下層節(jié)點需要處理復雜邏輯,里層嵌套定義另一個 idSetter 函數便可。我們可以把存在關聯的上下多層節(jié)點的邏輯控制代碼,都納入外層節(jié)點的 idSetter 函數中。

4.3 在 idSetter 編程的等效性

在 idSetter 函數中編寫代碼,等效于在 React class 的 render 函數中編碼。調用 render 函數,最后返回 “本節(jié)點定義”,idSetter 函數實際在 render() 調用中被調起的,相當于在 render() 入口位置,先調用 idSetter 函數。等效代碼如下所示:

function id__(comp) { // will call idSetter()
  // comp.state.xxx = xxx;
  // comp.$gui.comps = xxx;
}

class NewWTC extends T.BaseWTC_ {
  // ...
  render() {
    id__(this);
    var tagName = xxx, props = xxx, children = comp.$gui.comps;
    return React.createElement(tagName,props,children);
  }
}

本處代碼僅為概要示例,以偽碼方式解釋工作原理,xxx 表示省略過程的處理結果。其中嵌入的 id__ 函數會調用前面介紹的 idSetter 函數,只要在 idSetter 函數中本節(jié)點屬性更改,及針對子節(jié)點的更改被保存,render() 根據修改過的信息生成 React Element,就達到讓 idSetter 中編碼與 render 中編碼等效的目標。

與在 render 中編碼等效的 idSetter 函數舉例:

var fieldWidth = 0.9999;
var sTitle = "Temperature in Celsius";

function fieldset__(value,oldValue) {
  if (value <= 2) {
    // ...
    return;
  }
  
  this.duals.width = fieldWidth;
  utils.setChildren(this, [
    {sTitle} ,
    
  ]);
}

函數 utils.setChildren() 用來設置或更新子節(jié)點定義,需注意,各級子節(jié)點應指定 key 值,如果不指定,系統會認為你要創(chuàng)建新節(jié)點,而不是更新已存在節(jié)點。

盡管在 idSetter 的 value > 2 條件段編碼,等效于在 render 中編程,大部分情況下我們不必這么做(也盡量避免這么做)。因為 Shadow Widget 的雙源屬性功能很強大,邏輯控制總能分解的,把控制分解到雙源屬性的 setter 函數,或偵聽數據源變化來驅動特定動作,都能實現等效功能。這么細化分解,代碼更易理解,更好維護。

5. 高層設計過于 "函數式" 的陷阱

即便放棄 Shadow Widget 的可視化開發(fā)特性,只把它當作一個常規(guī)的 lib 庫使用也是很有價值的,主要表現在兩方面:

Shadow Widget 在虛擬 DOM 之上對四種構件關系(即:順序、包含、導航、層疊)做了封裝,像面板、導航、選項構件、彈窗等常用構件已現成可用,構造 GUI 更加便利。

JSX 與 idSetter 結合使用,既維持函數式編程風格,也克服原有 React 開發(fā)過于 "函數式" 的缺陷。

過于 “函數式” 對于界面類開發(fā)肯定不好,比如 UI 設計時,我們想擺一個文本框,再擺一個按鈕,分解設計的思路是,文本輸入變化了(onChange)該做什么,文本框輸入完成(鍵入了回車鍵)該做什么,按鈕被點擊后該怎么響應。細化設計的思考過程,是從界面一個個可視的 Component 出發(fā)的,是按對象化方式做分析的。不管你的代碼寫成啥樣,設計過程仍離不開一個個對象(如文本框、按鈕等),越是高層設計越是如此。

由于 React 偏愛函數式編程,加上 Flux 強化了數據流設計,容易引導大家一開始就從數據設計入手,著眼于數據如何分解、如何傳遞、如何驅動響應函數等。采用 Shadow Widget 后,產品開發(fā)會往面向對象設計拉回一些,把握這一點就容易理解 Shadow Widget 的設計精髓了。

本專欄歷史文章:

介紹一項讓 React 可以與 Vue 抗衡的技術

React 可視化開發(fā)工具 Shadow Widget 非正經入門(之一:React 三宗罪)

React 可視化開發(fā)工具 Shadow Widget 非正經入門(之二:分離界面設計)

React 可視化開發(fā)工具 Shadow Widget 非正經入門(之三:雙源屬性與數據驅動)

React 可視化開發(fā)工具 Shadow Widget 非正經入門(之四:flux、mvc、mvvm)

React 可視化開發(fā)工具 Shadow Widget 非正經入門(之五:指令式界面設計)

React 可視化開發(fā)工具 Shadow Widget 非正經入門(之六:markdown)

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

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83574.html

相關文章

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

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

    wenshi11019 評論0 收藏0
  • React 可視開發(fā)工具 shadow-widget 最佳實踐(上)

    摘要:上例的功能塊定義了如下節(jié)點樹入口節(jié)點是面板,結合該節(jié)點的函數書寫特點,我們接著介紹最佳實踐如何處理功能塊之內的編程。 本文介紹 React + Shadow Widget 應用于通用 GUI 開發(fā)的最佳實踐,只聚焦于典型場景下最優(yōu)開發(fā)方法。分上、下兩篇講解,上篇概述最佳實踐,介紹功能塊劃分。 showImg(https://segmentfault.com/img/bVWu3d?w=6...

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

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

    dongxiawu 評論0 收藏0

發(fā)表評論

0條評論

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