更新:“MakeNode”部件擴展
2011年9月12日,下午03:18由薩蒂揚| 在 發展中 ,YUI 3 畫廊| 7評論在我以前的文章, 一個YUI的3應用配方 ,我展示了一種使用Y.substitute作為一個非常基本的模板處理器。 從那裡生活的想法,建議#YUI IRC頻道的鄉親,和我做了一個Widget的延伸,是對YUI畫廊, 被稱為MakeNode。 MakeNode是不是一個通用的模板處理器,它不是作為一個意思。 另一方面,它是緊密集成的YUI 部件的基礎類,包括classname和事件傭工和國際化。 在這篇文章中,我將採取微調器的例子,並修改它,按照我以前的文章的準則和使用 MakeNode。MakeNode是作為一個畫廊組成部分以及修改後的微調組件,將在這篇文章中使用的例子。
擴展您的組件
要加載MakeNode,你需要包括在你的YUI().use() )使用的'gallery-makenode' “,或者如果定義通過一個YUI.add()列出它requires需要數組的聲明。 然後,延長你的widget,你列出的第三個參數Y.Base.create()像這樣:
Y。微調 = Y.Base.create( “微調”, Y。部件, [Y。MakeNode] { / /實例成員 ... }, { / /靜態成員 } );
,您可以添加沿任意數量的適當擴展部件,如WidgetParent,WidgetChild,WidgetStdMode MakeNode,等MakeNode增加了兩個開發商,所使用的_makeNode保護_locateNodes, _makeNode和_locateNodes,它會讀取從幾個靜態屬性,如果發現。
這個擴展的所有成員都是protected或private,因為他們是為了組件的開發和使用這些組件的實施者,誰不應該與他們的困擾。 記住要檢查“顯示受保護”選項, 查看API文檔時。
定義模板
你通常會做的第一件事是定義為您的組件的模板。 對於微調,我們的模板將是:
_template: <input type="text" title="{s input}" class="{c input}">“ “<button type="button" title="{s up}" class="{c up}"> </按鈕>”, “<button type="button" title="{s down}" class="{c down}"> </按鈕>” 加入(的'\ n'),
通常會被命名為默認模板_TEMPLATE和沿其他靜態屬性的類,如宣布ATTRS 。 MakeNode將使用此模板,如果沒有其他明文規定。 模板是純 HTML加了一系列括在大括號中,每一個單個字符(處理代碼)和一個或多個參數的佔位符。 佔位符和它們的產品是:
{@ attributeName}配置屬性的值{p propertyName}實例的屬性值{m methodName arg1 arg2 ….}返回值的方法。 其次是方法的名稱和任何數量由空格隔開的參數處理代碼。{c classNameKey}CSS Classname代替從生成_CLASS_NAMES靜態屬性(見_CLASS_NAMES屬性下面一節){s key}字符串從strings屬性,子屬性使用key。{? conditionvalueIfTrue valueIfFalse很像?:valueIfTruevalueIfFalse} ?:JavaScript的運營商,評估valueIfTrue如果條件truish,否則valueIfFalse。{1 condition valueIfOne valueIfMore }用於生產的基礎上,條件值的單/複數的話。{}任何其他值將處理Y.substitute不一樣。
例如, {@ value}將轉化為this.get('value')而{p value}轉換this['value']
當佔位符參數,如{m} {?}和{1}字符串必須括在雙引號。 數字,布爾值null null (所有不帶引號)將被解析到其正確的數據類型。 佔位符可以嵌套。 {?}和{1}佔位符通常會包含一個嵌套的佔位符條件和很可能對他們的價值觀,例如:
{P數量} {1 {P數量}“單位”,“單位”} 如果該屬性qty數量是1,它會"1 unit" “,2個或更多它將"2 units" “等。 處理與零一個更詳細的版本將是:
{? {P數量}“{P數量} {1 {P數量}”單位“,”單位“}”,“無”}
請注意,必須在其自己的一套引號括起來,處理內部的佔位符,如果一個字符串的結果。
要包括一個帶引號的字符串內的雙引號, \\" “雙反斜杠是必要的,因為JavaScript將解釋單一並丟棄前,先要到MakeNode僅允許雙引號。MakeNode不eval()以便解析器是有限的,但安全,什麼,但null ,空,布爾和雙引號的字符串將被忽略。
{?}佔位符也是得心應手地使用複選框和單選按鈕。 它可以用於生產的字符串"checked"根據處理指令的代碼如下真理價值。 因此, <input type="checkbox" {? {m getLength} "checked" ""}/> <input type="checkbox" {? {m getLength} "checked" ""}/>將產生顯著的複選框getLength方法返回什麼,但零。
{c}佔位符,我們需要有一個_CLASS_NAMES屬性定義。
進一步的佔位符,可以加入_templateHandlers他們_templateHandlers哈希添加到MakeNode。
_CLASS_NAMES財產
隨著ATTRS和_TEMPLATE靜態屬性,我們可以定義一個靜態屬性,它指向一個字符串_CLASS_NAMES _CLASS_NAMES 。 這些字符串都將被用於生成的className。 因此_CLASS_NAMES: ['input']會產生"yui3-spinner-input"的className 。 這些類名是存儲在實例屬性this._classNames 。 {c input}上面模板中的佔位符將"yui3-spinner-input"搖錢樹輸入“。 我呼籲在_CLASS_NAMES列出的字符串,例如'input' ,“的className 鍵 ”,因為它們可以作為一個關鍵,是指實際的className或包含這些類名的元素,我們將在後面看到。
您可以使用_CLASS_NAMES的屬性來生成任意數量的類名,無論你在模板中使用或不。 您仍然可以達到從內部this._classNames這些額外的類名。 產生的className使用yui3前綴NAME的靜態屬性的價值變成小寫,然後在給定的字符串_CLASS_NAMES (這一次不會變成小寫),全部由連字符分隔。 _classNames哈希也將包含為類名boundingBox contentBox ,首先根據"boundingBox"鍵和下第二個"content"鍵。 部件的boundingBox分配的值派生的類名NAME繼承鏈中的每個類的屬性, yui3-widget構件。 到MakeNode店this._classNames只有最頂層的className boundingBox 。
如果WidgetStdMod模塊被加載,MakeNode也將產生其作品HEADER , BODY和FOOTER與那些相同的密鑰,這也是在同一模塊中定義的常量部分。
如果一個組件是幾個層次從部件一樣, SuperSpecialSpinner繼承SuperSpinner繼承Spinner繼承Widget,如果其中的任何或_CLASS_NAMES _CLASS_NAMES屬性定義,MakeNode將產生所有類名和存儲在this._classNames 。 this._classNames 。 你並不需要包括在每個級別的名稱已經宣布在以前的水平。 事實上,它是更好的,你不會因為在每個級別產生的類名使用該級別的屬性值NAME名稱。 因此,在SuperSpecialSpinner , {c input}仍然會導致"yui3-spinner-input" “,而"yui3-superspecialspinner-input" “,所以它會保持你的CSS文件仍然有效。
{S}佔位符
構件有一個strings配置屬性定義,雖然它不與任何值初始化。 此屬性是為了保存字符串(或通過屏幕閱讀器,閱讀)的用戶是可見的。 重要的是,你永遠不包括直接在模板中可見的字符串。 這不是一個 MakeNode要求 - 它從未是一個好主意。 應始終被視為或讀給用戶的所有字符串放置在strings屬性。 strings屬性包含了每一個人的文字是由它的鍵位於哈希。 微調器組件有以下字符串,你可以看到上面模板中使用。
字符串:{ 值:{ 輸入:“按箭頭向上/下輕微的增量,主要增量頁面向上/向下鍵”, 起來:“增量”, 下來:“減” } },
這樣做的最好的部分是組件可以使用您的組件的開發人員本地化為其他語言很容易。 創建微調的一個實例時,您可以這樣做:
VAR mySpinner =新的微調({字符串:Y.Intl.get(“微調 ')}); 設置這樣的配置屬性中的strings替換默認strings值與使用先前定義的語言的語言資源文件。 {s}的佔位符訪問中存儲的字符串strings字符串屬性,無論是默認的或翻譯的,如果設置。 {s xxxx}佔位符幾乎是一樣使用{@ strings.xxxx}除了本地化替換字符串將進一步處理的佔位符。 這是翻譯的重要,因為語法為了從語言到語言不同,這使得改述的文本,包括其佔位符,以適應任何語言。 使用{@ strings.xxxx.yyyy.zzzz}這將使訪問嵌套更深的下跌,並防止進一步的替換字符串,字符串也可以訪問。 大括號可以包含在文字的{LBRACE} } {RBRACE} }佔位符。
使用renderUI _makeNode
我們使用模板來創建我們的組件的標記。 要做到這一點,我們可以調用MakeNode的_makeNode方法,是這樣的:
renderUI:函數(){ this.get追加(“contentBox)(this._makeNode()); },
這將填補在我們的widget contentBox處理模板的標記。 _makeNode方法返回的一個實例Y.Node可以追加或插入的任何地方或只是供以後使用。 它不會返回一個字符串,它會產生一個Node實例。 (如果你需要一個字符串,而不是一個節點,你可以使用_substitute方法,這就要求您在模板中通過。)
_makeNode方法需要兩個參數:一個參考模板和對象填寫佔位,作為Y.substitute 。 在我們簡單的微調例子,整個部件,但其他部件,可能需要幾個模板位和出件有一個單獨的模板。 在這種情況下,您通常會呼叫_makeNode的主要部分沒有參數,並調用不同的模板,它再次以填補額外的部分。 例如包含此renderUI方法:
renderUI:函數(){ VAR的fieldset = this._makeNode(); this.each(函數(項目){ fieldset.appendChild(this._makeNode(MultipleTemplates.RADIO_TEMPLATE,項目)); }); this.get('contentBox“)追加(字段集); }
_makeNode第一次調用返回一個Node的實例變量中fieldset fieldset 。 Y.ArrayList這樣的RADIO_TEMPLATE從存儲在數組列表中的項目和由此產生的附加 到節點的值fieldset的fieldset之前,最後contentBox的contentBox樣本組成部分,也是延長。 如特殊佔位{@} {p} }仍然指向的主要對象的屬性或屬性。 嵌套的項目將被處理一樣Y.substitute會。
_locateNodes方法
MakeNode進一步提供了_locateNodes方法將嘗試查找在聲明的類名的所有_CLASS_NAMES _CLASS_NAMES 。 為了找到特定的元素,您可以通過任意數量的className鍵,否則, _locateNodes嘗試所有。 對於每個的className每個元素, _locateNodes會產生一個私有的實例屬性,使用鍵名"Node" “後綴的下劃線前綴。 因此,在我們的微調例如_locateNodes _locateNodes將生成的_inputNode _inputNode _upNode _upNode _downNode _downNode 。 如果有多個元素具有相同的className, _locateNodes將返回到他們的第一個參考。 如果一個元素沒有被發現,沒有變量將被創建。
在微調組件,我們_locateNodes _locateNodes後創建的標記:
renderUI:函數(){ this.get(CBX)追加(this._makeNode()); this._locateNodes(); },
_EVENTS靜態屬性
一個進一步的屬性可以被定義沿著_TEMPLATE _template _CLASS_NAMES _CLASS_NAMES _EVENTS _EVENTS _EVENTS _EVENTS將包含一個散列類的名稱鍵,每一個包含事件的類型和方法來處理它們的哈希。 這是更好地用一個例子來解釋:
_EVENTS:{ 輸入:'變',/ /調用 this._afterInputChange boundingBox: { 類型:“鑰匙”, FN:“_onDirectionKey',/ /調用 this._onDirectionKey 參數:((Y.UA.opera)“下來:”:!“記者:”)+“38,40,33,34” }, “的mousedown'/ /調用 this._afterBoundingBoxMousedown ] 文件:“的MouseUp”,/ /調用 this._afterDocumentMouseup Y:“broadcastingObject:someEvent”/ /調用 [“_afterYBroadcastingObject:someEvent”] },
_EVENTS是與任意數量的條目的對象(哈希) 。 屬性的名稱,即哈希鍵,確定節點的事件,我們會聽取。 他們是相同的className定義鍵_CLASS_NAMES 。 有一些額外的特殊功能鍵:
"boundingBox"將參照邊界框本身。"document"是指文件包含這個widget。"THIS",是指在widget本身"Y"指YY實例。
如果部件已與WidgetStdMod以及延長,鍵HEADER , BODY和FOOTER將那些部分,因為他們將在_classNames哈希。 JavaScript並不需要被引用的鍵,如果他們是有效的標識符,因此上述都不需要被引用。
_EVENTS財產處理後renderUI , bindUI和syncUI方法被稱為所以部件預計將已經插入文檔正文內,否則, "document"標識將失敗。
對於每個元素有一個事件標識符或事件標識符的數組。 事件可以聽的事件或進一步的細節的對象的類型確定。 默認情況下,MakeNode將使用作為一個監聽器使用命名方法"_after"前綴,其次是與它的第一個字符的元素標識符資本化資本化與它的第一個字符的事件類型。 上面的代碼塊顯示為每個事件調用的方法。
事件標識符,也可以與屬性的type fn FN args args 。 該type是強制性的,並表示事件的類型,被聽到。 fn屬性給出的方法,將聽來的事件,從而避免了自動命名的名稱。 由於_EVENTS是靜態屬性,它已不能訪問,因此它不能採取一個實際的方法,只有它的名字。 this 可以使用args參數,通過進一步的論據,這需要一個鍵key的關鍵事件,如與來電。
MakeNode將使用Node.delegate聽內元素的boundingBox boundingBox,而它會Node.after Node.after聽取boundingBox boundingBox和文檔的主體。 它將使用this.after聽下的THIS這個關鍵Y.after Y.after根據上市Y Ÿ關鍵。 所有的事件都聽過的事件偵聽器後使用,因為他們是為了使部件響應事件,不過濾的對象,火災他們在任何情況下,這些事件可以預防或停止的行為。 (注:聽任何嵌套元素的key事件只與版本3.4.0pr1及以上的工程,因為代表團key關鍵事件是不是之前的所有其他功能的工作以及與以前的版本) 。
_EVENTS聲明是累積的,當組件從一個繼承。 繼承鏈中的每一個類都會有_EVENTS的_EVENTS聲明分開處理。
_ATTRS_2_UI靜態屬性
活動是雙向的,從 UI組件從組件到UI。 首先是由_EVENTS財產處理。 然後是屬性值的變化,需要體現在用戶界面的發射事件。 正如我在前一篇文章中,當有任何更改配置屬性二次效應中提到的, 他們應該更改的事件監聽器來處理, setter不是可選的setter屬性的方法,它應該只處理正常化所設置的值。 UI應該反映的配置屬性的狀態,首先syncUI syncUI,正在初始化,然後每個屬性改變事件。 對於後者,我們需要附加一個事件監聽器,我們通常會在bindUI 。 部件已經提供了一個機制,使簡單,這是我在以前的文章評論中描述。
部件使用實例屬性_UI_ATTRS包含與另外兩個屬性,對象SYNC和BIND 。 這些上市最初同步,然後聽取以反映當前值保持UI的配置屬性的名稱是一個數組。 部件預計每個條目有與之相關聯的方法,由前綴的屬性名後的第一個字符轉換為大寫,在適當的駱駝方法名稱的屬性_uiSet命名_uiSet的。 因此,如果"value" 在任何上市_UI_ATTRS陣列(無論SYNC BIND BIND),小部件會期望找到_uiSetValue _uiSetValue方法。 此方法將接受兩個參數,該value被設置和src的變化。 這是對我們的微調_uiSetValue代碼_uiSetValue方法:
_uiSetValue:功能(價值,SRC){ (SRC === UI),{ 回報; } this._inputNode.set(值,this.get(格式化)(值)); },
你在這段代碼中看到對應的字符串常量的所有大寫字母標識符宣布在其他地方,讓 YUI壓縮到做得更好。 ,基本上,該方法設置的value在HTML屬性<input>方塊,新設置的值,被格式化後。 提及到TextBox提供了_locateNodes 。 src參數的初步檢查,看看是否設置為字符串值'ui' 如果是這樣的話,會採取任何行動。 這是為了避免無限循環。 如果用戶在輸入框中輸入的東西,其價值將value價值配置屬性,然後valueChange火valueChange事件, _uiSetValue得到_uiSetValue所謂,如果任其發展下去,然後去改變輸入框的值,這將再次引發整個過程。 _uiSetValue ,因此,如果我們知道變化從UI,我們什麼也不做,所以打破循環。 然而,這需要另一塊代碼的其他地方。 DOM事件監聽器,當我們設置的配置屬性,我們使用第三個可選參數設置,這樣:
_afterValueChange:功能(EV){ this.set(值,ev.newVal,{SRC:界面}); }
這是我們確保,從 UI的變化從而標記,然後檢查相同的標誌,以避免循環。 不要使用標識src SRC時設置的屬性,而不是source的源泉,將無法識別。
這一切說,我還沒有談到本節的標題中提到的_ATTRS_2_UI屬性_ATTRS_2_UI。 由於在我以前的文章顯示,通過我在他們的失誤,確保正確列出所有屬性影響的UI是有些凌亂。 你不應該初始化_UI_ATTRS從頭開始,因為構件已經列出了一大堆的屬性和那些會丟失。 你要串連現有的,這有點很難記住如何做是正確的,新的屬性名稱。 為了簡單,MakeNode將讀取靜態屬性_ATTRS_2_UI ,並為你做,串聯。 它將連接所有這些名單,從每類繼承鏈中的每個級別,每個類都可以處理自己的屬性。 在微調,我們有:
_ATTRS_2_UI:{ BIND:VALUE 同步:VALUE },
MakeNode將接受的名稱,數組或單一的屬性名稱,在這種情況下。
問題自然就出現了,為什麼兩個列表,一個用於同步約束力? SYNC是首次周圍, renderUI和bindUI方法後,如果它們存在,被稱為前syncUI而那些上市BIND將被綁定到為以後的變化,相應的屬性。 常常SYNC陣列比少項BIND清單,這是因為組件的模板可能已經配置屬性相同的默認值,也沒有必要做一個初步的同步。 所以,如果的value配置屬性的默認值是一個空字符串“ <input>模板中的value沒有價值屬性,那麼有沒有必要在初始化同步。
中列出的屬性BIND將_uiSet Xxxx以任何順序調用的方法,屬性可以以任何順序設置。 屬性SYNC上市將在它們上市前他們的繼承者的祖先者的順序被調用一次,因此如果一個依賴於另一個(不應該),順序可能很重要。
MakeNode將檢查在這些陣列中的任何重複的條目。 如果任何出現,它意味著已經處理此屬性和任何新的聲明將最有可能超越我們的一個類組件繼承_uiSet Xxxx為它的處理程序。 順便說一下,MakeNode在_CLASS_NAMES重複的條目,這也可能導致在一些衝突雖然不是所有的情況下還檢查。 MakeNode將消息寫入任何這樣的錯誤日誌。
_PUBLISH財產
最後, _PUBLISH靜態屬性將列出這些事件予以公佈。 它包含一個散列,使用事件的名稱作為其鍵和對象的文字作為其值的配置屬性。 它會公佈所有的繼承鏈中的任何此類財產中列出的所有事件。 同一事件的名稱,可以發表在一個類,在任何類從它繼承,這將使後來者的配置屬性將覆蓋在年紀稍長的。 例如,你可能想使現有的全球賽事轉播。 正如_EVENTS財產,因為_PUBLISH是得不到的靜態屬性,當指定的功能,這是該方法的名稱,作為一個字符串,需要給予。 this
結論
MakeNode提供了一個非常簡單的模板處理器,與功能,是高度集成的部件基礎類。 它還提供了輔助方法創建在模板中使用的類名,並使用這些名稱來定位和參考節點。 它還提供了掛接到由UI組件本身所產生的事件和與之相關的每一個方法的手段。 它所有這些事情,同時注意尊重繼承鏈向上伸直Widget和你可以定義任何類的水平。
它不提供絕對的一切可能性,但其中涵蓋了良好的範圍。 然而,它並不妨礙你增加額外的功能。 你可能很少有寫一個bindUI或syncUI方法,如果您使用膠水MakeNode提供,但你可以這樣做,因為MakeNode不使用他們。
作為畫廊那些有耐心看完,到目前為止,我還修改了安東尼Pipkin的圖庫組件的按鈕設置,並在手風琴和TimeSpinner組件,所有可用的獎金。
分享和擴展: 書籤del.icio.us | Digg它! | 書籤交易!


嗯,令人叫絕。 最後通過這篇文章,我躍躍欲試畫廊模塊。 看來,我不知道很多的腳手架 *如*是偉大而不在戰壕裡第一個被以銳為開發新的,但我可以肯定看它如何能縮短一些重複的代碼,特別是對於我們這些有在:-)已經把我們的時間。
我好奇以下聲明:“_EVENTS財產後 renderUI,bindUI和syncUI方法處理所以被稱為 widget的預期已經插入文檔正文內,否則,”文件“標識符將失敗。”一般情況下,正在呈現的一個小部件,並不一定意味著它是在DOM中,我經常呈現一個部件,尚未插入包含的節點,它工作得很好,只要我不嘗試到DOM達到。
因此,只想要使用“文件”標識符或一般,它會導致處理失敗時,一個問題是在聲明中的問題? 我不知道是否應先檢查 _LOCATE_NODES功能,回落到DOM檢查,必要時?
兩個偉大的(如果不是長)的文章和畫廊模塊的感謝。
乙
評論布賴恩J ·米勒 - 9月12日,2011年#
布賴恩
如果您在_EVENTS使用“文件”標識符和組件是不附加到文檔,它會被忽略。 此外,“文件”將參考組件的文件,否的主要原因之一或在一個 iframe。
_locateNodes將組件是否連接到文件或,因為它搜索的boundingBox內,否則可能會選擇與其他組件實例在同一類名的元素。
評論薩蒂揚 - 2011年9月13日, #
由於薩蒂揚。 節省時間改進部件書面。
我沒去搞清楚模塊依賴通過一個小的麻煩。 從 8月的版本似乎沒有 _EVENTS射擊。 但是,一旦想通了,使用一個更近的畫廊版本,它的偉大工程。
我沒有把一個簡單的例子,只是為了顯示最基本的部件,用巫裸要求MakeNode可能會有所幫助:
https://github.com/JohnICello/yui-samples
評論由約翰Iannicello - 2011年9月16日#
你有沒有考慮到一個單獨的畫廊模塊中分裂出夢幻般的模板處理器的嗎?
評論Lindal約翰 - 2011年9月22日, #
約翰 ,
這是有趣的問題,因為整個項目模板的事情開始。 這就是為什麼它是所謂 MakeNode後,它是什麼,所以要求回去一個階段是其唯一的,那麼公共方法,makeNode。 但它可能是有意義的,讓我們看到的數字:
當前的調試版本是23.7k,縮小的版本4.68k,五分之一(API文檔,我把太多的評論)。 直到3.4.1出來,這個版本包括一個修補 Y.substitute。 一旦是,縮小的推移3.87k,換句話說,該補丁需要17%。
如果我剝離不相關的模板一切,(我也平均下降_locateNodes)下降到2.13k。 這意味著模板的已佔 55%的模塊。 我不知道是否是值得的分裂。
我還以為自己模板的一部分,也許是三分之一,所以它本來的意義下降,其餘的包。 這個數字是否有意義?
包括_locateNodes,這是那麼得心應手,一旦你使用_makeNode,其餘全部結束被畢竟不是那麼多。
評論薩蒂揚- 2011年9月22日, #
我似乎沒有能夠保持這個模塊安靜。
我添加了兩個新功能:
如果使用MakeNode也沒有任何這些類繼承它有一個 renderUI方法,它會自動為您創建一個附加的處理 _template contentBox,然後結果沒有一個 _locateNodes。
我也加入了{n}的佔位符將採取的處理代碼和參數序列和承擔的第一個值是一個對象,它會使用過程中的第二。
因此,
{np objRef @ attr}將讀取屬性objRef,假設值是一個對象和讀取屬性attr。 它只能處理代碼作為參數的簡單標識符(不{M})。評論薩蒂揚- 2011年9月29日, #
新增:
_EVENTS描述符有一個新的選擇,其處理。 除了“型”,“FN”和“參數”的屬性,你現在有'當'。
如果沒有指定,則默認為“後”。 它也可以被“前”和“委託”。 它決定哪一種方法,它使用附加的事件,無論 Y.after(默認),Y.on(“前”)或Y.delegate(“代表”)。
默認命名的事件偵聽器方法的改變,因為現在不只是一個“_after”前綴,方法,現在就可以開始與“_before'或'_delegate”。
評論薩蒂揚- 2011年10月21日, #