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