聯(lián)合使用 CSS、JavaScript 和 JSF 精心打造 Ajax 應(yīng)用程序,第 1 部分: 增強(qiáng) JSF 頁(yè)面的外觀[zhuan]
幾乎每個(gè) JSF HTML 組件都有兩個(gè)可選屬性,分別為 style
和 styleClass
,這兩個(gè)屬性在 HTML 輸出中呈現(xiàn)為 style
和 class
屬性。一些組件,比如 <h:dataTable>
和 <h:panelGrid>
,還有針對(duì)于其 facet 的額外樣式屬性。本節(jié)討論與 CSS 相關(guān)的 JSF HTML 庫(kù)屬性。
如果 Web 頁(yè)面具有獨(dú)特的樣式,可以在頁(yè)面頁(yè)眉的 <style>
元素內(nèi)定義樣式規(guī)則。也可以使用 style
屬性為單個(gè) JSF 組件指定樣式信息。但在大多數(shù)情況下,您可能更愿意在單獨(dú)的 CSS 文件中包含樣式規(guī)則,以便可以將這些樣式規(guī)則應(yīng)用到多個(gè)頁(yè)面。可以使用 <link>
標(biāo)記將外部樣式表鏈接到一個(gè) Web 頁(yè)面,如清單 1 所示:
清單 1. 使用 <link> 標(biāo)記
|
|
在清單 1 中,href
屬性包含絕對(duì) URI。也可以為 CSS 文件使用相對(duì)鏈接,但如果 JSF 頁(yè)面包含 /faces/
前綴,最好是在上下文路徑中包含 ${pageContext.request.contextPath}
或 <%=request.getContextPath()%>
。在這種情況下,任何鏈到 CSS 文件、圖像或其他資源的相對(duì)鏈接都將導(dǎo)致一個(gè)包含 /faces/
前綴的 HTTP 請(qǐng)求,這意味著非 JSF 文件將由 Faces servlet 處理。這雖然可以工作,但效率并不高。若使用 .faces
后綴請(qǐng)求 JSF 頁(yè)面,則盡可以放心地在基于 JSF 的應(yīng)用程序中使用相對(duì)鏈接,因?yàn)檫@樣可以消除上述問(wèn)題。
CSS 文件包含一些樣式表規(guī)則,這些規(guī)則可以應(yīng)用于 JSF 組件能夠呈現(xiàn)的 HTML 元素,也可以被簡(jiǎn)單地包含在 JSF 頁(yè)面的組件之間。比如,如果希望只有將鼠標(biāo)放到鏈接上時(shí)才出現(xiàn)下劃線,則可以使用如下規(guī)則(參見(jiàn)清單 2):
清單 2. 鏈接的樣式規(guī)則
|
這些規(guī)則可應(yīng)用于任何鏈接,無(wú)論 <a>
元素是直接包含在 JSF 頁(yè)面還是由諸如 <h:commandLink>
這樣的 JSF 組件生成(參見(jiàn)清單 3):
清單 3. HTML 和 JSF 鏈接
|
清單 4 給出了如何為 JSF 組件指定內(nèi)聯(lián)樣式。
清單 4. 具有樣式屬性的 JSF 組件
|
然而在大多數(shù)情況下,都是在 CSS 文件中定義樣式類(參見(jiàn)清單 5),以便可以將相同的樣式規(guī)則應(yīng)用于多個(gè)組件。
清單 5. 樣式類示例
|
此樣式類的名稱將會(huì)通過(guò) styleClass
屬性提供給 JSF 組件,如清單 6 所示。
清單 6. 具有 styleClass 屬性的 JSF 組件
|
清單 1-6 的代碼可以從本文的示例代碼鏈接給出的 LinkStyles.jsp
和 LinkStyles.css
文件中找到(參見(jiàn) 下載)。
正如之前所提到的,一些 JSF 組件具有多個(gè)樣式屬性。例如,<h:message>
和 <h:messages>
就有如下所示的 10 個(gè)與 CSS 相關(guān)的屬性:
-
style
-
styleClass
-
errorClass
-
errorStyle
-
fatalClass
-
fatalStyle
-
infoClass
-
infoStyle
-
warnClass
-
warnStyle
根據(jù)所呈現(xiàn)的消息的嚴(yán)重程度,只有兩個(gè)屬性會(huì)應(yīng)用到每個(gè)消息。UISelectOne
和 UISelectMany
組件的 JSF 標(biāo)記接受所呈現(xiàn)的列表項(xiàng)的 enabledClass
和 disabledClass
屬性。<h:dataTable>
和 <h:panelGrid>
標(biāo)記 則有針對(duì)主表、頁(yè)眉、頁(yè)腳、行和列的類屬性。下面的示例展示了如何使用與 CSS 相關(guān)的數(shù)據(jù)表屬性,這個(gè)數(shù)據(jù)表在下面的屏幕截圖中給出。
圖 1. TableStyles 示例

首先,需要為這個(gè)表組件建立數(shù)據(jù)模型。OrderBean
類(如清單 7 所示)擴(kuò)展了 javax.faces.model.ArrayDataModel
。實(shí)際的應(yīng)用程序會(huì)從數(shù)據(jù)庫(kù)中獲得模型的數(shù)據(jù),但為了簡(jiǎn)便起見(jiàn),OrderBean
將由一個(gè)靜態(tài)數(shù)組初始化。
清單 7. OrderBean 示例
|
ItemBean
類(參見(jiàn)清單 8)具有三個(gè)讀/寫屬性(description
、quantity
、unitPrice
)和一個(gè)只讀屬性(itemPrice
)。
清單 8. ItemBean 示例
|
TableStyles.css
文件(如清單 9 所示)包含用于此數(shù)據(jù)表的樣式。
清單 9. TableStyles.css 示例
|
TableStyles.jsp
示例(參見(jiàn)清單 10)包含一個(gè) JSF 表組件,該組件使用在 TableStyles.css
中定義的樣式類。styleClass
屬性的值用于 <table>
元素。headerClass
和 footerClass
屬性為此表的頁(yè)眉和頁(yè)腳單元格指定樣式。columnClasses
屬性包含用于數(shù)據(jù)單元格的 <td>
元素的類的列表(用逗號(hào)分隔)。
另外一個(gè)類的列表通過(guò) rowClasses
屬性指定。這些類用于此表的 <tr>
元素。在 TableStyles.jsp
示例中,只有兩個(gè)行類,但此表卻有 6 行。<h:dataTable>
組件的 JSF 呈現(xiàn)器會(huì)交替使用這兩個(gè)樣式類,為第一、三和五行使用 graybg
類,為第二、四和六行使用 whitebg
類。var
屬性定義一個(gè)變量,稱為 row
,可用來(lái)在呈現(xiàn)期間訪問(wèn)當(dāng)前行的數(shù)據(jù)。全部數(shù)據(jù)從 orderBean
模型獲得,該模型通過(guò) value
屬性綁定到此表。
清單 10. TableStyles.jsp 示例
|
清單 11 給出了由 TableStyles.jsp
頁(yè)面生成的 HTML。
清單 11. 由 TableStyles.jsp 生成的 HTML
|
TableStyles.jsp
示例中的 JSF 表的最后一個(gè) <h:column>
組件使用 footerClass
屬性為顯示訂單總額的頁(yè)腳單元格指定兩個(gè)類。footer
和 number
類將會(huì)用于頁(yè)腳單元格的 <td>
元素。<h:column>
組件的 footerClass
屬性只在 JSF 1.2 中可用。如果使用的是較早的 JSF 版本,則必須包裝能在 <div>
元素內(nèi)呈現(xiàn)總額的 <h:outputText>
組件,以便可以添加 number
類的對(duì)齊效果(參見(jiàn)清單 12)。源代碼的壓縮文件包含針對(duì) JSF 1.1 和 JSF 1.2 的代碼示例。
清單 12. JSF 1.1 版本的 TableStyles.jsp 示例
|
在構(gòu)建具有很多 JSF 頁(yè)面的大型應(yīng)用程序時(shí),您可能不喜歡手動(dòng)設(shè)置每個(gè)組件實(shí)例的 styleClass
屬性。標(biāo)準(zhǔn)的 JSF HTML 組件沒(méi)有默認(rèn)樣式,但是您將在本節(jié)中看到,可以遍歷此 JSF 組件樹(shù)并程序化地設(shè)置默認(rèn)的樣式類。要實(shí)現(xiàn)此操作,需要知道這些樹(shù)是如何創(chuàng)建的以及此 HTML 是如何生成的。
所有的 face 請(qǐng)求均由 Faces Servlet 截獲,這是在每個(gè)基于 JSF 的 Web 應(yīng)用程序的 web.xml
描述符中配置的。對(duì)于每個(gè)請(qǐng)求,F(xiàn)aces Servlet 都會(huì)初始化 javax.faces.context.FacesContext
對(duì)象并調(diào)用 javax.faces.lifecycle.Lifecycle
實(shí)例的 execute()
和 render()
方法。execute()
方法處理 JSF 請(qǐng)求處理生命周期中除最后一個(gè)階段(Render Response)之外的每個(gè)階段,最后的這個(gè)階段由 render()
方法執(zhí)行。
|
在第一個(gè)階段(名為 Restore View),JSF 實(shí)現(xiàn)獲取應(yīng)用程序的視圖處理程序,它是一個(gè) javax.faces.application.ViewHandler
實(shí)例,如果請(qǐng)求是一個(gè) post back(比如,用戶單擊了提交按鈕),還會(huì)調(diào)用 restoreView()
方法。在這種情況下,此組件樹(shù)應(yīng)該在處理之前的 Faces 請(qǐng)求期間構(gòu)造和保存(參見(jiàn)側(cè)欄 狀態(tài)保存方法)。
如果當(dāng)前的請(qǐng)求不是一個(gè) post back(比如,用戶單擊了一個(gè) Faces 鏈接),JSF 實(shí)現(xiàn)調(diào)用當(dāng)前 FacesContext
的 renderResponse()
方法和 ViewHandler
實(shí)例的 createView()
方法。renderResponse()
調(diào)用會(huì)指導(dǎo) JSF 實(shí)現(xiàn)由當(dāng)前的 Restore View 階段跳到 Render Response 階段。默認(rèn)視圖處理程序的 createView()
方法只創(chuàng)建一個(gè) javax.faces.component.UIViewRoot
組件。此樹(shù)的其余部分將會(huì)在 Render Response 階段創(chuàng)建,在該階段 JSF 實(shí)現(xiàn)調(diào)用視圖處理程序的 renderView()
方法。
不管是恢復(fù)還是創(chuàng)建組件樹(shù),JSF 實(shí)現(xiàn)都會(huì)在 renderView()
方法執(zhí)行期間的某個(gè)階段將 HTTP 請(qǐng)求轉(zhuǎn)發(fā)給相關(guān)的 JSF 頁(yè)面。比如,如果請(qǐng)求 /MyApp/MyPage.faces
或 /MyApp/faces/MyPage.jsp
,那么所執(zhí)行的 JSF 頁(yè)面的 URI 就是 /MyApp/MyPage.jsp
。
任何 JSF 頁(yè)面都包含組件標(biāo)記,比如 <f:view>
和 <h:form>
,這些標(biāo)記都受 JSP 標(biāo)記處理程序支持。這是一些 Java™ 類,它們實(shí)現(xiàn)在 javax.servlet.jsp.tagext
包中定義的接口。當(dāng)執(zhí)行此頁(yè)時(shí),JSP 容器會(huì)創(chuàng)建標(biāo)記處理程序的實(shí)例并調(diào)用它們的方法。JSF 1.2 組件的所有標(biāo)記處理程序都擴(kuò)展了 javax.faces.webapp.UIComponentELTag
。如果使用的是 JSF 1.1 API,則此標(biāo)記處理程序類擴(kuò)展 javax.faces.webapp.UIComponentTag
或
javax.faces.webapp.UIComponentBodyTag
。不管使用的是哪個(gè) JSF 版本,如果組件樹(shù)沒(méi)有在 Restore View 階段恢復(fù),JSF 標(biāo)記處理程序?qū)?huì)在 Render Response 階段創(chuàng)建組件實(shí)例。
您可能會(huì)嘗試通過(guò)實(shí)現(xiàn) javax.faces.event.PhaseListener
來(lái)設(shè)置默認(rèn)的樣式,但當(dāng)用戶以單擊鏈接或在 Web 瀏覽器中輸入 URL 的方式請(qǐng)求頁(yè)面時(shí),這種方法不會(huì)生效。在這種情況下,JSF
實(shí)現(xiàn)不能恢復(fù)組件樹(shù),此樹(shù)必須在 Render Response
階段創(chuàng)建。在最后階段之前,組件樹(shù)并不存在,在呈現(xiàn)了響應(yīng)之后再更新組件樣式就太晚了,因?yàn)?HTML
輸出已經(jīng)生成。因此,默認(rèn)的樣式必須在呈現(xiàn)組件之前的 Render Response 階段執(zhí)行期間設(shè)置。
JSF 組件有一個(gè)有趣的只讀屬性,稱為 rendersChildren
。如果該屬性為 false
,只有 encodeBegin()
和 encodeEnd()
方法會(huì)被調(diào)用來(lái)呈現(xiàn)此組件。如果 getRendersChildren()
返回 true
,那么 encodeChildren()
也會(huì)在 Render Response 階段被調(diào)用。這些方法通常會(huì)將呈現(xiàn)指派給另一個(gè)類,該類必須實(shí)現(xiàn) javax.faces.render.Renderer
接口,但 JSF 組件也可以生成 HTML,無(wú)需使用呈現(xiàn)器。
當(dāng)使用 JSF 1.1 時(shí),編碼方法最初都由標(biāo)記處理程序方法調(diào)用。但是,如果組件呈現(xiàn)自身的子組件,那么嵌套組件的所有標(biāo)記處理程序都會(huì)停止調(diào)用編碼方法,因?yàn)槌尸F(xiàn)將會(huì)由另一些組件負(fù)責(zé),這些組件的 getRendersChildren()
方法返回 true
。這種在 JSF 1.1 中實(shí)現(xiàn)的呈現(xiàn)過(guò)程十分有效,因?yàn)樗鼘⒕彌_降到了最低,但它需要應(yīng)用程序開(kāi)發(fā)人員在 <f:verbatim>
組件中包含 HTML 內(nèi)容。在 JSF 1.2 中,由于呈現(xiàn)只會(huì)在整個(gè)組件樹(shù)創(chuàng)建之后才執(zhí)行,所以不需要使用 <f:verbatim>
。
不管使用的是 JSF 1.1 還是 1.2,只要調(diào)用了 encodeChildren()
,嵌套組件都會(huì)被完全初始化并準(zhǔn)備好被呈現(xiàn)。因此,此時(shí)就是設(shè)置默認(rèn)樣式的最佳時(shí)機(jī)。接下來(lái),您會(huì)看到如何創(chuàng)建一個(gè)定制組件來(lái)為它的所有嵌套組件設(shè)置 styleClass
屬性,遞歸遍歷 JSF 組件樹(shù)。
這里所展示的技巧可以用來(lái)設(shè)置 JSF 組件的任何屬性,而不僅僅是默認(rèn)的樣式。因而,最好是創(chuàng)建一個(gè)可重用的通用基類。SetupComponent
類擴(kuò)展 JSF API 的 UIComponentBase
類,并定義一個(gè)名為 setup()
的抽象方法,可以對(duì)支持呈現(xiàn)的每個(gè)嵌套組件調(diào)用該方法。setupTree()
方法(如清單 13 所示)執(zhí)行 JSF 組件樹(shù)的遞歸遍歷。
清單 13. SetupComponent 類的 setup() 和 setupTree() 方法
|
繼承自 UIComponentBase
的 getRendersChildren()
方法(參見(jiàn)清單 14)被覆蓋以返回 true
,以便設(shè)置組件能夠控制其子組件的呈現(xiàn)。
清單 14. SetupComponent 類的 getRendersChildren()方法
|
清單 15 中所示的 encodeChildren()
方法被覆蓋,以便在為每個(gè)子組件調(diào)用 encodeTree()
之前調(diào)用 setupTree()
。
清單 15. SetupComponent 類的 encodeChildren() 方法
|
encodeTree()
方法(參見(jiàn)清單 16)為當(dāng)前組件調(diào)用編碼方法,如果 getRendersChildren()返回 false
,則還會(huì)為子組件遞歸調(diào)用此方法。
清單 16. SetupComponent 類的 encodeTree() 方法
|
清單 17 中所示的 DefaultStylesComponent
類擴(kuò)展 SetupComponent
并實(shí)現(xiàn) setup()
方法,以設(shè)置 styleClass
屬性,此屬性的值構(gòu)建在組件系列的名稱和呈現(xiàn)器的名稱之上。
清單 17. DefaultStylesComponent 類
|
DefaultStylesComponent
在 faces-config.xml
中配置,如清單 18 所示。
清單 18. 在 faces-config.xml 中配置 DefaultStylesComponent
|
DefaultStylesTag
類(參見(jiàn)清單 19)擴(kuò)展由 JSF 1.2 API 定義的
UIComponentELTag
類,并實(shí)現(xiàn) getComponentType()
和 getRendererType()
方法以分別返回 DefaultStylesComponent
和 null
。如果使用的是 JSF 1.1,標(biāo)記類必須擴(kuò)展 UIComponentTag
,而非 UIComponentELTag
。
清單 19. DefaultStylesTag 類
|
css.tld
文件(如清單 20 所示)定義了定制標(biāo)記的 defaultStyles
名稱和屬性。對(duì) id
、binding
和 rendered
屬性的支持均繼承自 UIComponentELTag
。
清單 20. 用于 JSF 1.2 和 JSP 2.1 的 css.tld 文件
|
如果使用的是 JSF 1.1,TLD 文件應(yīng)該遵從 JSP 1.2 規(guī)范定義的語(yǔ)法(參見(jiàn)清單 21)。
清單 21. 用于 JSF 1.1 和 JSP 1.2 的 css.tld 文件
|
|
本節(jié)中給出的 JSF 示例展示了如何使用背景顏色和邊框來(lái)增強(qiáng) JSF 組件的外觀。
圖 2. DefaultStyles 示例

清單 22 展示的是 DefaultStyles.css
文件,該文件定義了幾個(gè)用于 DefaultStyles.jsp
示例的樣式類。
清單 22. DefaultStyles.css 示例
|
DefaultStyles.jsp
示例 (參見(jiàn)清單 23)使用了 <css:defaultStyles>
組件為不具有 styleClass
屬性的 JSF 組件設(shè)置默認(rèn)樣式。其中的一個(gè)組件使用 SpecialInputText
樣式類。EnabledOption
和 DisabledOption
類用于下拉列表項(xiàng)。
清單 23. DefaultStyles.jsp 示例
|
清單 24 給出了由 DefaultStyles.jsp
頁(yè)面產(chǎn)生的 HTML。您將注意到所有的表單元素都有一個(gè) class
屬性。以 Default
開(kāi)始的那些類名均由 <css:defaultStyles>
組件設(shè)置。
|
清單 24. DefaultStyles.jsp 產(chǎn)生的 HTML
|
本文討論了標(biāo)準(zhǔn) JSF 組件提供的 CSS 支持。簡(jiǎn)單的組件只有兩個(gè)可選屬性,分別為 style
和 styleClass
。
更復(fù)雜的組件,比如網(wǎng)格和數(shù)據(jù)表,則會(huì)有針對(duì)其 facet 和元素的額外的 CSS 屬性。本系列的這一部分還介紹了 JSF
如何構(gòu)建組件樹(shù),以及如何在組件呈現(xiàn)之前遍歷這些組件樹(shù)以便可以添加特性,比如默認(rèn)樣式。請(qǐng)繼續(xù)留意本系列的第 2 部分,在該部分您將會(huì)獲得可以讓
JSF 表單更加動(dòng)態(tài)的基于 JavaScript 的技巧。
![]() |
![]()
|
描述 | 名字 | 大小 | 下載方法 |
---|---|---|---|
本文的示例應(yīng)用程序 | jsfcssjs_part1_src.zip | 25KB | HTTP |
![]() |
||||
![]() |
關(guān)于下載方法的信息 | ![]() |
學(xué)習(xí)
-
您可以參閱本文在 developerWorks 全球站點(diǎn)上的 英文原文。
- developerWorks Web 開(kāi)發(fā)專區(qū) 包含 Web 2.0 開(kāi)發(fā)所需的工具和信息。
- 獲得更多有關(guān) JSF 技術(shù) 的信息并將其應(yīng)用到您的應(yīng)用程序中。
-
developerWorks Ajax 資源中心 包含了不斷增加的 Ajax 內(nèi)容庫(kù)和有用的資源,可以讓您立即開(kāi)始開(kāi)發(fā) Ajax 應(yīng)用程序。
-
JSF 1.2 Specification 全面描述了 JavaServer Faces 技術(shù)。
- W3C 提供了一個(gè)關(guān)于 級(jí)聯(lián)樣式表 (CSS) 的出色介紹。
獲得產(chǎn)品和技術(shù)
-
從 javaserverfaces.dev.java.net 獲得 JSF RI 源代碼和二進(jìn)制文件。
- Apache MyFaces Project 是另一個(gè)流行的 JSF 實(shí)現(xiàn)。
posted on 2008-03-11 12:57 gembin 閱讀(1356) 評(píng)論(0) 編輯 收藏 所屬分類: JSF