对于我的一个JSF / primefaces项目,我想显示自给定日期以来经过的时间 - 想想“此条目最后一次编辑3小时前3小时”。
首先,我计算了支持bean中的时间间隔,并让视图轮询它。这意味着每秒一次ajax调用,也很容易破坏 - 不好。
所以我为这个任务制作了我的第一个简单的JSF复合组件。基本上它只是h的一个包装器:outputText:它将开始日期作为属性,然后在Javascript中,它每秒计算到当前日期的时间间隔,并相应地更新outputText。
以下是代码:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
<composite:attribute name="start" />
</composite:interface>
<composite:implementation>
<div id="#{cc.clientId}" class="elapsedTime">
<h:outputText id="outTxt" value="#{cc.attrs.start}" />
</div>
<script type="text/javascript">
var outTxt = document.getElementById("#{cc.clientId}:outTxt");
var a = outTxt.innerHTML.split(/[^0-9]/);
var baseDate = new Date(a[0], a[1] - 1, a[2], a[3], a[4], a[5]);
function timeStringFromSeconds(s)
{
var hours = Math.floor((s / 86400) * 24);
var minutes = Math.floor(((s / 3600) % 1) * 60);
var seconds = Math.round(((s / 60) % 1) * 60);
if (minutes < 1) {
minutes = "00";
} else if (minutes < 10) {
minutes = "0" + minutes;
}
if (seconds < 1) {
seconds = "00";
} else if (seconds < 10) {
seconds = "0" + minutes;
}
return(hours + ":" + minutes + ":" + seconds);
}
function update() {
var currentDate = new Date();
var elapsed = (currentDate - baseDate) / 1000;
outTxt.innerHTML = timeStringFromSeconds(elapsed);
}
update();
setInterval(update, 1000);
</script>
</composite:implementation>
</html>
这是按预期工作的。但是,由于我无法直接从JS检索start属性值,我让h:outputText首先显示日期值,然后JS将从呈现的HTML中检索它并将其替换为已用时间。
因此,虽然我立即更新了值,但在某些浏览器/设备上,原始日期值可以短暂显示。整个事情对我来说就像一个丑陋的解决方法。如果由于某种原因我想使用第二个属性,我根本无法使用它,所以这种方法显然是有限的/破坏的。
所以我的问题是:是否有更简洁的方法来做到这一点,例如直接访问属性(如果可能的话)?
或者这只是你在复合材料中无法做到的事情?
非常感谢!
答案 0 :(得分:4)
通过仅在第一次遇到组件时呈现函数,可以避免JS函数冲突。如果您愿意将JS外部化,则可以包含xhtml中的所有内容。请BalusC
查看此帖<cc:interface/>
<cc:implementation>
<h:outputScript target="head" name="js/myJs.js"/>
<div id="#{cc.clientId}">
<h:outputText id="output" value="#{cc.attrs.value}" />
<script>
update("#{cc.clientId}:output");
setInterval(update, 1000, "#{cc.clientId}:output");
</script>
</div>
</cc:implementation>
或者,您可以使用componentType
的{{1}}属性完成此操作,然后使用<cc:interface/>
注释注释Java类。在Java类中,如果还没有,您可以覆盖@FacesComponent(name=...
将JS写入响应。
这是复合
encodeBegin
和Java代码
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:cc="http://java.sun.com/jsf/composite">
<cc:interface componentType="jsTestComp" />
<cc:implementation>
<div id="#{cc.clientId}">
<h:outputText id="output" value="#{cc.attrs.value}" />
<script>
update("#{cc.clientId}:output");
setInterval(update, 1000, "#{cc.clientId}:output");
</script>
</div>
</cc:implementation>
</html>
答案 1 :(得分:2)
由于ForguesR已经pointed out,您可以使用timeago jQuery plugin。
我拿了插件并将其包装成JSF component。只需添加此依赖项:
<dependency>
<groupId>com.github.jepsar</groupId>
<artifactId>timeago-jsf</artifactId>
<version>1.0</version>
</dependency>
此命名空间:
xmlns:ta="http://jepsar.org/timeago"
现在,您可以使用java.util.Date
属性传递value
来使用该组件:
<ta:timeAgo value="#{bean.date}" />
jQuery是从PrimeFaces,BootsFaces或timeago组件加载的。
基于JSF UIViewRoot#getLocale()
自动加载本地化脚本。
答案 2 :(得分:1)
实际上这不是JSF问题。您只需要使用JSF检索初始值并将其传递给脚本。而不是重新发明轮子看看http://timeago.yarp.com/。以下是演示页面中的一个简单示例:
<time class="timeago" datetime="2008-07-17T09:24:17Z">July 17, 2008</time>
这将输出:9 years ago
。
与axemoi建议一样,将值作为参数传递。类似的东西:
Last modified : <time class="loaded timeago" datetime="#{YourBean.lastEdited}">#{YourBean.lastEdited}</time>