Tapestry 5組件事件詳解
組件事件
組件事件是指組件所察覺到的用戶的行為,如點(diǎn)擊鏈接或提交表單。
組件主要用于兩種用途:
◆它們呈現(xiàn)了用戶在客戶端瀏覽器中觸發(fā)鏈接或表單發(fā)起的請(qǐng)求。這些在頁面導(dǎo)航(page navigation)和請(qǐng)求處理(requst processing)中有更全面的描述。
◆它們描繪了一個(gè)請(qǐng)求中的控制流即允許一個(gè)組件通知它的容器一些情境(一個(gè)表單被提交),或者從容器中收集一些片斷數(shù)據(jù)。
通常,一個(gè)導(dǎo)航請(qǐng)求(由用戶發(fā)起)將產(chǎn)生許多控制流請(qǐng)求。如,表單組件被將一個(gè)動(dòng)作請(qǐng)求觸發(fā),然后發(fā)送通知事件聲稱表單提交事件將被處理,隨后不管成功與否。
Tapestry 4中,你可以用一個(gè)方法名來配置組件的一個(gè)參數(shù),當(dāng)某一特定事件發(fā)生時(shí)(通常來自客戶端的請(qǐng)求)該方法將被調(diào)用。如:
﹤form jwcid=”@Form” listener=”listener:someMethodName”﹥
這有一些局限性,包括事實(shí)上僅有一個(gè)方法被調(diào)用。
Tapestry 5組件事件引入了通過命名約定或者OnEvent annotation來標(biāo)識(shí)的事件處理方法(event handler methods)。事件處理方法可以有任何的可見性,甚至私有的(通常它們是包可見性的,用以支持測試)。
同比于Tapestry 5組件事件配置一個(gè)被調(diào)用的特定的方法,你可以標(biāo)識(shí)一個(gè)或多個(gè)方法來監(jiān)聽組件事件。單獨(dú)的一個(gè)事件處理方法可以接收許多不同組件的通知事件,如在事件處理方法上加上@OnEvent(component={"component1", "component2"})。
比如,這里是一個(gè)讓用戶選擇1到10數(shù)字的頁面片斷(就叫"chooser"):
- ﹤p﹥ Choose a number from 1 to 10: ﹤/p﹥
- ﹤p﹥
- ﹤t:count end="10" value="index"﹥
- ﹤a t:id="select" t:type="actionlink" context="index"﹥${index}﹤/t:comp﹥
- ﹤/t:count﹥
- ﹤/p﹥
ActionLink組件創(chuàng)建一個(gè)動(dòng)作URL。
URL標(biāo)識(shí)了頁面包含的組件("chooser"),事件的類型(除非不是默認(rèn)且很通常的"action"事件類型),頁面里組件的id("select")還有附加的上下文(context)值。
一個(gè)URL示例:http://localhost:8080/chooser.select/3.
當(dāng)存在附加的上下文值時(shí),它們被追加到路徑中。
這里示范了Tapestry與傳統(tǒng)方式URL的關(guān)鍵區(qū)別,它是一個(gè)面向動(dòng)作的框架。這里的URL并不是說鏈接被點(diǎn)擊時(shí)發(fā)生了什么,而是標(biāo)識(shí)哪個(gè)組件來響應(yīng)。
沒有從URL到一段代碼的簡單映射;這里通過調(diào)用事件處理方法的形式來替代Tapestry 5組件事件發(fā)送通知事件。當(dāng)組件生成的鏈接被用戶點(diǎn)擊時(shí),一個(gè)Java方法將會(huì)被調(diào)用。
- @OnEvent(component = "select")
- void valueChosen(int value)
- {
- _value = value;
- }
Tapestry在此做了兩件事:
◆確認(rèn)valueChosen()方法作為調(diào)用的方法。
◆將上下文值從字符串轉(zhuǎn)換為整數(shù)并傳送給事件處理方法。
在上面的實(shí)例中,valueChosen()方法將在choose組件產(chǎn)生任何事件時(shí)被調(diào)用(至少有一個(gè)上下文值)。因?yàn)锳ctionLink組件僅產(chǎn)生單個(gè)事件類型,即"action",這不會(huì)帶來任何問題(OnEvent可以配置事件類型)。
某些組件能產(chǎn)生多種事件,些時(shí)你需要更多的細(xì)節(jié)參數(shù):
- @OnEvent(value = "action", component = "select")
- void valueChosen(int value)
- {
- _value = value;
- }
OnEvent annotation的value屬性用來匹配事件名。
"action"是默認(rèn)的事件類型名,ActionLink 和 Form組件都使用這個(gè)事件類型。如果你省略了OnEvent annotation的component參數(shù),它就是收到所有包含組件的通知事件,可能包括內(nèi)嵌組件(因?yàn)槭录芭輽C(jī)制event bubbling)。
你可以限定接收哪個(gè)或哪些組件的事件。
事件處理方法命名約定
作為使用annotations的一種替代,我們可以以指定的方式命名事件,Tapestry 5組件事件將會(huì)調(diào)用你的方法,就好像方法被聲明了annotation一樣。
這種事件處理方法的命名方式以前綴"on"開頭,緊跟著動(dòng)作的名字(首字母大寫capitalized),然后加上"From" 和一個(gè)首字母大寫的組件id。
先前的例子可以寫成:
- void onActionFromSelect(int value)
- {
- _value = value;
- }
如果事件類型命名為"onAny",它將接受所有事件類型,我們很少需要此種方式!
如果出于某些難解的原因我們需要以同一方法接收不同組件的相同事件,我們就需要OnEvent annotation。
來自Howard的提示:我發(fā)現(xiàn)我更喜歡命名約定方式,保留annotation只是為了其他不適合的情況。
事件上下文(Event Context)
上下文值(ActionLink組件的context參數(shù))可以是任何對(duì)象,然而,僅發(fā)生一個(gè)簡單的字符串轉(zhuǎn)換。與Tapestry 4相比,他有一個(gè)精細(xì)的類型機(jī)制,怪名叫"DataSqueezer"。
此外,不管是什么值(string, number, date),它都會(huì)被轉(zhuǎn)換為文本字符串。這將形成一個(gè)更可讀的URL。
如果帶有多個(gè)上下文值(通過將一個(gè)對(duì)象list或數(shù)組綁定到ActionLink的context參數(shù)),則每一個(gè)值都將有序地追加到URL中。
當(dāng)一個(gè)Tapestry 5組件事件事件處理方法被調(diào)用時(shí),將發(fā)生一個(gè)強(qiáng)制(coercion)從字符串到實(shí)際類型的轉(zhuǎn)換。事件處理方法僅當(dāng)上下文值的數(shù)量至少與方法參數(shù)數(shù)量一致時(shí)被調(diào)用,帶有過多參數(shù)的方法將被跳過。
另外,一個(gè)事件處理方法還可以帶上一個(gè)java.lang.Object[]類型的參數(shù)。這個(gè)參數(shù)會(huì)接收整個(gè)上下文數(shù)組。這在上下文不同時(shí)間為不同長度時(shí)有用處。我們可以使用一個(gè)個(gè)顯式的參數(shù)或者單個(gè)的Object[]類型的參數(shù)。
事件冒泡(Event Bubbling)
事件會(huì)冒泡向上傳遞到層級(jí),直到它被終止。事件在事件處理方法返回一個(gè)非null值時(shí)終止。對(duì)于頁面導(dǎo)航事件,事件處理方法的返回決定了Tapestry將如何呈現(xiàn)響應(yīng)。
【編輯推薦】