我的问题是如何实现一个共同的布局,所有我的JSF 2页面,只有内容部分的页面刷新,而不是整个页面,每当我从一个不同的面板点击链接/菜单。我使用Facelets方法,它做我想要的,除了每次我单击面板中的链接(例如菜单项从左面板)整个页面刷新。我正在寻找的是一种方法,只刷新我的页面的内容部分。为了说明这一点,我的目标pagelayout。
<h:panelGroup id="header" layout="block"> <h1>Header</h1> </h:panelGroup> <h:panelGroup id="menu" layout="block"> <h:form> <f:ajax render=":content"> <ul> <li><h:commandLink value="include1" action="#{bean.setPage('include1')}" /></li> <li><h:commandLink value="include2" action="#{bean.setPage('include2')}" /></li> <li><h:commandLink value="include3" action="#{bean.setPage('include3')}" /></li> </ul> </f:ajax> </h:form> </h:panelGroup> <h:panelGroup id="content" layout="block"> <ui:include src="/WEB-INF/includes/#{bean.page}.xhtml" /> </h:panelGroup>
用这个bean:
@ManagedBean @ViewScoped public class Bean implements Serializable { private String page; @PostConstruct public void init() { page = "include1"; // Default include. } // +getter+setter. }
在这个例子中,实际的包含模板是include1.xhtml,include2.xhtml和include3.xhtml在/ WEB-INF / includes文件夹(文件夹和位置是完全免费的你的选择;文件只是放在/ WEB-INF通过猜测浏览器地址栏中的URL可以将其设置为prevent direct access)。
然而,当< ui:include>时,这一切都在Mojarra(不是MyFaces)页面依次包含< h:form>。任何回发将失败,因为它完全缺少视图状态。你可以使用在这个答案h:commandButton/h:commandLink does not work on first click,works only on second click中找到的脚本来解决这个问题,或者如果你已经在使用JSF实用程序库OmniFaces,使用它的FixViewState script,或者如果你已经使用PrimeFaces并且只使用< p:xxx> ajax,那么它已经被透明地考虑。
此外,确保您使用最低限度Mojarra 2.1.18,因为旧版本将无法保持视图范围bean活着,导致在回发期间使用错误的包。如果你不能升级,那么你需要回到下面的(相对笨拙的)有条件地渲染视图的方法,而不是有条件地构建视图:
... <h:panelGroup id="content" layout="block"> <ui:fragment rendered="#{bean.page eq 'include1'}"> <ui:include src="include1.xhtml" /> </ui:fragment> <ui:fragment rendered="#{bean.page eq 'include2'}"> <ui:include src="include2.xhtml" /> </ui:fragment> <ui:fragment rendered="#{bean.page eq 'include3'}"> <ui:include src="include3.xhtml" /> </ui:fragment> </h:panelGroup>
缺点是视图将变得相对较大,并且所有相关联的被管理的bean可能被不必要地初始化,即使当它们根据渲染条件不被使用时。
至于元素的定位,这只是一个应用正确的CSS的问题。这超出了JSF的范围:)至少,< h:panelGroup layout =“block”>呈现一个< div> ;,所以应该是足够好。 最后但并非最不重要的是,这种SPA(单页应用)方法不是SEO友好的。所有页面都不能由searchbots索引,也不能由终端用户标记,你可能需要在客户端中使用HTML5历史记录,并提供服务器端回退。此外,对于具有表单的页面,同样的视图范围bean实例将在所有页面中重复使用,从而导致返回到先前访问的页面时出现不直观的范围行为。我建议去模板化的方法,而不是在这个答案的第二部分概述:How to include another XHTML in XHTML using JSF 2.0 Facelets?另请参见How to navigate in JSF? How to make URL reflect current page (and not previous one)。