如何在JSF Facelets文件中根据标志切换两个ui:composition?
嘿,这个需求在JSF里完全能搞定,根本不需要虚构的magic:if标签!下面给你几个实用的方案,按需选就行:
方案1:用JSF原生的
ui:fragment + rendered属性(推荐) 这是最稳妥的方式,ui:fragment是JSF核心组件,不会生成多余的HTML代码,完全适配JSF的生命周期,支持动态切换。
假设你的切换标志是托管Bean里的布尔属性(比如#{bean.showCompositionA}),代码示例如下:
<!-- 当标志为true时渲染组合A --> <ui:fragment rendered="#{bean.showCompositionA}"> <ui:composition template="/templates/main.xhtml"> <ui:define name="content"> <h2>这是组合A的内容</h2> <p>可以在这里放任意JSF组件、HTML内容</p> </ui:define> </ui:composition> </ui:fragment> <!-- 当标志为false时渲染组合B --> <ui:fragment rendered="#{not bean.showCompositionA}"> <ui:composition template="/templates/main.xhtml"> <ui:define name="content"> <h2>这是组合B的内容</h2> <p>和组合A的结构、内容可以完全不同</p> </ui:define> </ui:composition> </ui:fragment>
说明:rendered属性会在视图渲染阶段根据EL表达式的结果决定是否渲染对应的片段,就算用户交互后标志发生变化(比如点击按钮切换),页面也能正确更新。
方案2:用
h:panelGroup(适合需要HTML容器的场景) 如果你需要给切换的内容包裹一个HTML容器(比如<div>或<span>),可以用h:panelGroup替代ui:fragment,用法几乎一样:
<h:panelGroup rendered="#{bean.showCompositionA}" layout="block"> <ui:composition template="/templates/main.xhtml"> <ui:define name="content">组合A内容(包裹在div里)</ui:define> </ui:composition> </h:panelGroup> <h:panelGroup rendered="#{not bean.showCompositionA}" layout="block"> <ui:composition template="/templates/main.xhtml"> <ui:define name="content">组合B内容(包裹在div里)</ui:define> </ui:composition> </h:panelGroup>
说明:layout="block"会生成<div>,layout="inline"生成<span>,如果不指定layout,默认是inline。
方案3:用JSTL的
c:if标签(注意生命周期差异) 如果你切换的标志是页面加载时就确定的静态值(不会在用户交互中变化),也可以用JSTL的c:if标签,但要注意它的执行时机:JSTL标签是在视图构建阶段执行的,只会运行一次,后续标志变化不会触发重新渲染。
首先需要引入JSTL核心标签库:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
然后使用c:if:
<c:if test="#{bean.showCompositionA}"> <ui:composition template="/templates/main.xhtml"> <ui:define name="content">组合A内容(静态条件)</ui:define> </ui:composition> </c:if> <c:if test="#{not bean.showCompositionA}"> <ui:composition template="/templates/main.xhtml"> <ui:define name="content">组合B内容(静态条件)</ui:define> </ui:composition> </c:if>
警告:如果你的标志是动态变化的(比如用户点击按钮切换),千万别用这个方案,因为c:if不会重新执行,页面不会更新。
额外优化:模板相同的情况简化代码
如果两个组合用的是同一个模板,完全可以把模板部分抽出来,只切换ui:define里的内容,这样代码更简洁:
<ui:composition template="/templates/main.xhtml"> <ui:define name="content"> <ui:fragment rendered="#{bean.showCompositionA}"> <!-- 组合A的内容 --> <h2>组合A专属内容</h2> </ui:fragment> <ui:fragment rendered="#{not bean.showCompositionA}"> <!-- 组合B的内容 --> <h2>组合B专属内容</h2> </ui:fragment> </ui:define> </ui:composition>
这种方式减少了重复代码,维护起来更方便。
内容的提问来源于stack exchange,提问作者battmanz
相关产品推荐
相关产品推荐

