roy*_*osa 34 jsf facelets uiinclude single-page-application ajax-update
我正在学习JSF 2,感谢我在这么短的时间里学到了很多东西.
我的问题是关于如何为我的所有JSF 2页面实现一个公共布局,并且每当我从另一个面板单击一个链接/菜单时,只有页面的内容部分不刷新整个页面.我使用Facelets方法它做了我想做的事情,除了每次我点击一个面板的链接(例如左面板的菜单项)时,整个页面都会刷新.我正在寻找的是一种只刷新页面内容部分的方法.为了说明这一点,我的目标是pagelayout.
没有发布我的代码,因为我不确定Facelets是否可以这样做.除了Facelets之外,还有其他方法更适合我的要求吗?
Bal*_*usC 62
一个简单的方法是以下视图:
<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>
Run Code Online (Sandbox Code Playgroud)
有了这个bean:
@ManagedBean
@ViewScoped
public class Bean implements Serializable {
private String page;
@PostConstruct
public void init() {
page = "include1"; // Default include.
}
// +getter+setter.
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,实际包含模板include1.xhtml
,include2.xhtml
并include3.xhtml
在/WEB-INF/includes
文件夹(文件夹和位置是完全自由的选择;文件只是放置/WEB-INF
,以防止直接访问通过猜测在浏览器的地址栏中的URL).
这种方法适用于所有MyFaces版本,但需要至少Mojarra 2.3.0.如果您使用的是早于2.3.0的Mojarra版本,那么当<ui:include>
页面依次包含a 时,这一切都会失败<h:form>
.任何回发都将失败,因为它完全缺少视图状态.您可以通过升级到最低限度Mojarra 2.3.0或使用此答案中的脚本来解决此问题h:commandButton/h:commandLink在第一次单击时不起作用,仅在第二次单击时起作用,或者如果您已经在使用JSF实用程序库OmniFaces,使用其FixViewState脚本.或者,如果您已经使用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>
Run Code Online (Sandbox Code Playgroud)
缺点是视图将变得相对较大,并且即使不按照呈现条件使用它们,也可能不必要地初始化所有关联的被管理bean.
至于元素的定位,这只是应用正确的CSS的问题.这超出了JSF的范围:)至少,<h:panelGroup layout="block">
渲染一个<div>
,所以应该足够好.
最后但并非最不重要的是,这种SPA(单页应用程序)方法不是SEO友好的.所有页面都不能被搜索机器人编入索引,也不能被最终用户收藏,您可能需要在客户端中摆弄HTML5历史记录并提供服务器端备份.此外,对于带有表单的页面,同一个视图范围的bean实例将在所有页面中重用,导致在您导航回以前访问过的页面时出现不直观的作用域行为.我建议采用模板方法,如本答案的第2部分所述:如何使用JSF 2.0 Facelets在XHTML中包含另一个XHTML?另请参见如何在JSF中导航?如何使URL反映当前页面(而不是之前的页面).
归档时间: |
|
查看次数: |
43205 次 |
最近记录: |