摘要:本篇講解轉(zhuǎn)義標(biāo)簽投影定義,這幾項與如何分離界面設(shè)計有關(guān)。找一個替代品如上一篇非正經(jīng)入門之一所述,要克服漿糊的不利影響,要找一個替代品。本文完本專欄歷史文章介紹一項讓可以與抗衡的技術(shù)可視化開發(fā)工具非正經(jīng)入門之一三宗罪
本系列博文從 Shadow Widget 作者的視角,解釋該框架的設(shè)計要點。本篇講解轉(zhuǎn)義標(biāo)簽、json-x、投影定義,這幾項與 "如何分離界面設(shè)計" 有關(guān)。
?
1. 找一個 JSX 替代品如上一篇 "非正經(jīng)入門(之一)" 所述,Shadow Widget 要克服 "JSX漿糊" 的不利影響,要找一個 JSX 替代品。
比如下面 JSX 表達方式:
returnDear {user.name}, {welcomeMsg(user)}
;
等效于:
return React.createElement( H1, {id:user.id}, "Dear ", user.name, ", ", welcomeMsg(user) );
創(chuàng)建一個 Element,需傳遞三項信息:ReactClass,props,children 列表。我們把這三項改造成一個 array 數(shù)組格式:
[ [ReactClass, props], child1, child2... ]
其中,child1, child2 是子節(jié)點定義,格式是 string 字串,或 array 數(shù)組。這種以 array 數(shù)組表達一個 Element 節(jié)點的格式叫 json-x 描述方式,與 JSX 完全等效。
2. 轉(zhuǎn)義標(biāo)簽為了方便在 html 網(wǎng)頁文件中描述用戶界面,我們定義 "轉(zhuǎn)義標(biāo)簽" 的表達方式,如下:
Referece: example.com
轉(zhuǎn)義標(biāo)簽無非將所有 HTML 標(biāo)簽劃分為行內(nèi)標(biāo)簽與 block 標(biāo)簽,前者用 表達,后者用 在轉(zhuǎn)義標(biāo)簽中定義的屬性,比如上面的 src="http://example.com",在掛載前先整理出 props 表(如 {src:"http://example.com"}),而轉(zhuǎn)義標(biāo)簽的上下級節(jié)點的從屬關(guān)系,以及同級節(jié)點之間的前后關(guān)系,指明了 json-x 數(shù)據(jù)中的 children 定義。所以,ReactClass,props,children 三項信息都有了,轉(zhuǎn)義標(biāo)簽?zāi)苻D(zhuǎn)換成 json-x,所以它與 JSX 也是等效的。 轉(zhuǎn)義標(biāo)簽具有良好可讀性,所以,它在 *.html 文件中可以直接書寫。另外,這種格式對搜索引擎也友好,若依賴 JSX 定義界面,搜索引擎無法分析 html 文件中定義了什么信息。 React 支持服務(wù)側(cè)渲染,這個特性似乎鼓勵了其生態(tài)鏈上若干工具額外拓展服務(wù)側(cè)功能。比如 react-router 中 Router 組件的 history 屬性,既可以是 browserHistory,也可以是 hashHistory。對于前者,客戶側(cè)路由(即 URL 路徑)決定服務(wù)側(cè)如何實現(xiàn),將兩側(cè)的設(shè)計捆綁起來的,后者 hashHistory(即 #/some/path)完全在客戶側(cè)自主決定,與服務(wù)側(cè)無關(guān)。很顯然,后一方式優(yōu)于前者,前者違背了軟件設(shè)計的 "關(guān)注點分離"(Separation of concerns, SOC)原則,并且在實踐上,服務(wù)側(cè)只有用 webpack-dev-server (加 --history-api-fallback 參數(shù))才能玩得好,不只綁架用 JS 語言,而且綁架用特定工具。要命的是,react-router 官方居然推薦大家首選 browserHistory。 這個 browserHistory 就是充滿妖氣的特性,怪里怪氣,表面看起來有用,實則禁不起推敲。React 的 propTypes 也很妖,官方讓它存活了這么久,最終決定在 v15.5 之后棄用,連 context 也不建議用了,context 本是 React 為緩解跨節(jié)點數(shù)據(jù)共享不便,弄出的不倫不類的東西。 某種程度上 React 的服務(wù)側(cè)渲染也多少沾點 "妖氣",有些人僅為了解決 SEO 優(yōu)化用它,仔細想想有點本末倒置了。它的初始需求源于 google 之類的搜索引擎不認 JSX,因為 JSX 服務(wù)于編程,編程腳本原不該由搜索引擎關(guān)注的,該關(guān)注的只是一些靜態(tài)文本。處理靜態(tài)文本沒必要拉上 React 一家子吧?但事實卻是,我們非得套用一個客戶側(cè)編程風(fēng)格,用 JS 開發(fā)的服務(wù)側(cè)渲染工具,你說妖不妖? 在分離界面之前,我們還需建立路徑索引機制。 Shadow Widget 通過一顆樹(Widget 樹,R 樹)管理由它定義的界面,各節(jié)點都有 key 值作標(biāo)識,既可以顯示指定一個 key 值,也可以缺省,缺省時由系統(tǒng)自動生成一個數(shù)字來表示。這果顆樹的根節(jié)點是 ".body",如果根節(jié)點下有一個 key 值為 "toolbar" 的 Panel 節(jié)點,它的絕對路徑就是 ".body.toolbar"。 有了路徑索引機制,我們能將界面描述與它的行為定義分離開了。比如這么定義界面: 這么定義 Test 按鈕的行為: 界面的轉(zhuǎn)義標(biāo)簽在 *.html 文件中書寫,界面元素的行為定義在 *.js 文件進行,如此,界面設(shè)計分離出來了,界面描述與相關(guān)元素的行為定義通過該元素的絕對路徑實現(xiàn)關(guān)聯(lián)。如上例,用 javascript 編寫某元素的行為定義,也稱 "投影定義"。 json-x 數(shù)據(jù)與轉(zhuǎn)義標(biāo)簽都與 JSX 對等,但傳遞 props 數(shù)據(jù)有若干限制,比如轉(zhuǎn)義標(biāo)簽不支持傳遞函數(shù)對象,json-x 可傳函數(shù)對象,但也不鼓勵(主要因為不規(guī)范)。函數(shù)定義應(yīng)在投影類中定義,就像上面舉例的 $onClick 函數(shù),不通過轉(zhuǎn)義標(biāo)簽的屬性來傳遞,只在轉(zhuǎn)義標(biāo)簽掛載時,到 main 下找到相應(yīng)投影定義,然后捆綁相應(yīng)的函數(shù)定義。 除了函數(shù),描述復(fù)雜的 props 數(shù)據(jù)時,json-x 的表達能力是完整的,因為它本來就是 javascript 數(shù)據(jù),但轉(zhuǎn)義標(biāo)簽受 html 標(biāo)簽格式的影響,要改用 JSON 字串來表示,比如: 屬性值用 "{" 與 "}" 括起來,表示它是 JSON 字串,用 JSON.parse 前要先刪掉首尾兩個花括號,如上面 width 值為 JSON.parse("400")。另外,對于 string 類型的屬性值,可以直接傳遞(避開字串首尾是花括號的情形),不必按 JSON 字串的方式,如上面 title 屬性。 實施界面與底層分離除了投影定義,還有一種指定 idSetter 函數(shù)的方式,若簡單去理解,該方式是投影定義的一個變種,同樣實現(xiàn)特定界面元素的行為定義的動態(tài)綁捆。 舉例來說,界面這么描述: Javascript 這么定義: 這種書寫方式與上面投影定義的方式是等效的,投影類中該在 getInitialState() 中書寫的代碼,要挪到 idSetter 函數(shù)的 if (value == 1) 分支中,該在 componentDidMount() 中書寫的代碼移到 if (value == 2) 的分支中,該在 componentWillUnmount() 中書寫的代碼移到 if (value == 0) 的分支中。 使用 idSetter 函數(shù)的優(yōu)點是,相應(yīng)界面節(jié)點的絕對路徑不必完整定義,即路徑上各段不必顯式給出 key 值,系統(tǒng)由 $id__="xxx" 屬性值,自動找出 idSetter 函數(shù)。另一個優(yōu)點是,編程風(fēng)格更加函數(shù)式。 Flux 框架要求節(jié)點間數(shù)據(jù)流向要遵守嚴(yán)格的約束,React 不惜犧牲編程便利性,刻意隱藏了內(nèi)建的那顆虛擬 DOM 樹,導(dǎo)致編程中跨節(jié)點調(diào)用非常不便,各節(jié)點都被一層黑墻包裹,無法探知周圍都有哪些節(jié)點存在,好在 React 為這個黑墻開了一扇單向玻璃窗:refs,讓父節(jié)點可以引用子節(jié)點,子節(jié)點引用不了父節(jié)點??朔貌槐愕慕馑幨且?redux 那樣的框架,把存在交叉影響的兩個或多個節(jié)點中的數(shù)據(jù),提升到一個公共區(qū)域去編程。 既然 Shadow Widget 引入 MVVM 框架,在 Component 的 API 層面限制節(jié)點間互通已不合時宜,單向數(shù)據(jù)流應(yīng)該在更高層面的設(shè)計去保證。所以,Shadow Widget 引入了 "W 樹" 的概念,也就是,所有符合規(guī)格的 Component 節(jié)點(即源于 WTC 類創(chuàng)建的節(jié)點)都串接在一顆樹上。樹中各節(jié)點都有唯一 "路徑" 標(biāo)示,節(jié)點之間還可以用 "相對路徑" 或 "絕對路徑" 引用,比如: 有了 W 樹設(shè)計,router 規(guī)劃將變得簡單明了,比方下圖界面,把兩個可切換的頁 Article 與 Talk 裝到一個導(dǎo)航面板(NavPanel)中,若想切換到 Article 頁,按 "/article" 導(dǎo)航,切換另一頁用 "/talk" 導(dǎo)航。 ? (本文完) 本專欄歷史文章: 介紹一項讓 React 可以與 Vue 抗衡的技術(shù) React 可視化開發(fā)工具 Shadow Widget 非正經(jīng)入門(之一:React 三宗罪) 文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。 轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/87046.htmlmain[".body.toolbar.p.btn1"] = {
$onClick: function(event) {
alert("clicked");
},
};
idSetter["btn1"] = function(value,oldValue) {
if (value <= 2) {
if (value == 1) { // init process
this.setEvent( {
$onClick: function(event) {
alert("clicked");
},
});
// ...
}
else if (value == 2) { // did mount
// ...
}
else if (value == 0) { // will unmount
// ...
}
return;
}
// render process ...
};
this.componentOf("http://") // get parent component
this.componentOf("http://brother") // brother node
this.componentOf("sub.child") // child node
this.componentOf("./seg.child") // by relative path
this.componentOf(".body.top.toolbar") // by absolute path
摘要:前言非正經(jīng)入門是相對正經(jīng)入門而言的。不過不要緊,正式學(xué)習(xí)仍需回到正經(jīng)入門的方式。快速入門建議先學(xué)會用拼文寫文檔注冊一個賬號,把庫到自己名下,然后用這個庫寫自己的博客,參見這份介紹。會用拼文寫文章,相當(dāng)于開發(fā)已入門三分之一了。 本系列博文從 Shadow Widget 作者的視角,解釋該框架的設(shè)計要點,既作為用戶手冊的補充,也從更本質(zhì)角度幫助大家理解 Shadow Widget 為什么這...
摘要:本篇解釋中類的控制指令,與指令式界面設(shè)計相關(guān)。本專欄歷史文章介紹一項讓可以與抗衡的技術(shù)可視化開發(fā)工具非正經(jīng)入門之一三宗罪可視化開發(fā)工具非正經(jīng)入門之二分離界面設(shè)計可視化開發(fā)工具非正經(jīng)入門之三雙源屬性與數(shù)據(jù)驅(qū)動可視化開發(fā)工具非正經(jīng)入門之四 本系列博文從 Shadow Widget 作者的視角,解釋該框架的設(shè)計要點。本篇解釋 Shadow Widget 中類 Vue 的控制指令,與指令式界面...
閱讀 2149·2023-04-26 03:06
閱讀 3601·2023-04-26 01:51
閱讀 2099·2021-11-24 09:38
閱讀 2471·2021-11-17 17:00
閱讀 2341·2021-09-28 09:36
閱讀 951·2021-09-24 09:47
閱讀 2593·2019-08-30 15:54
閱讀 1566·2019-08-30 15:44