在看之前项目的代码中发现,查询条件中的日期限制(即开始日期和结束日期)是在后台加以验证的,至于前台无任何限制,表现效果如下:
现可以将效果优化显示如下:
|
|
核心代码:
<p:ajax event="dateSelect" process="@this,searchStartTime,searchEndTime" update="searchEndTime" />
具体代码实现:
<p:calendar pattern="yyyy-MM-dd" maxlength="10" readonlyInput="true" id="searchStartTime"
showOtherMonths="true" size="11" navigator="true"
yearRange="c-10:c+10" converterMessage="抽取日期,格式输入不正确!"
showButtonPanel="true" maxdate="#{mgrbean.searchStartMaxDate}" styleClass="myCalendar1"
value="#{mgrbean.searchStartTime}" >
<p:ajax event="dateSelect" process="@this,searchStartTime,searchEndTime" update="searchEndTime" />
</p:calendar>
~
<p:calendar pattern="yyyy-MM-dd" maxlength="10" readonlyInput="true" id="searchEndTime"
showOtherMonths="true" size="11" navigator="true"
yearRange="c-10:c+10" converterMessage="抽取日期,格式输入不正确!"
showButtonPanel="true" mindate="#{mgrbean.searchEndMinDate}" maxdate="new Date()" styleClass="myCalendar1"
value="#{mgrbean.searchEndTime}" >
<p:ajax event="dateSelect" process="@this,searchStartTime,searchEndTime" update="searchStartTime" />
</p:calendar>
后台:
/**查询条件:开始日期*/
private Date searchStartTime;
/**查询条件:结束日期*/
private Date searchEndTime;
/**查询开始日期最大日期*/
private Date searchStartMaxDate;
/**查询结束日期最小日期*/
private Date searchEndMinDate;
public Date getSearchExtractStartMaxDate() {
if(null == this.searchExtractEndTime){
return new Date();
}
return searchExtractEndTime;
}
public void setSearchExtractStartMaxDate(Date searchExtractStartMaxDate) {
this.searchExtractStartMaxDate = searchExtractStartMaxDate;
}
public Date getSearchExtractEndMinDate() {
return this.searchExtractStartTime;
}
public void setSearchExtractEndMinDate(Date searchExtractEndMinDate) {
this.searchExtractEndMinDate = searchExtractEndMinDate;
}
使用后发现BUG:在点击日期弹框中的清空按钮,不会触发dateSelect,导致日期限制未重置
查看源码后发现,点击清空按钮时,只是给input框调了一下val(’’),不会触发任何事件,源码如下:
解决思路:若能够在清空时触发onchange事件,问题便能迎刃而解
具体实现如下:
- 页面中重写pluglin日期选择清空按钮事件,手动触发change事件: jQuery(j).change();
//重写Pluglin日期选择按钮事件
(jQuery).datepicker._attachHandlers = function(i) {
var h = this._get(i, "stepMonths")
, j = "#" + i.id.replace(/\\\\/g, "\\");
i.dpDiv.find("[data-handler]").map(function() {
var k = {
prev: function() {
(jQuery).datepicker._adjustDate(j, -h, "M")
},
next: function() {
(jQuery).datepicker._adjustDate(j, +h, "M")
},
hide: function() {
jQuery(j).val("");
jQuery(j).change();
(jQuery).datepicker._hideDatepicker()
},
today: function() {
(jQuery).datepicker._gotoToday(j)
},
selectDay: function() {
(jQuery).datepicker._selectDay(j, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
return false
},
selectMonth: function() {
(jQuery).datepicker._selectMonthYear(j, this, "M");
return false
},
selectYear: function() {
(jQuery).datepicker._selectMonthYear(j, this, "Y");
return false
}
};
(jQuery)(this).bind(this.getAttribute("data-event"), k[this.getAttribute("data-handler")])
})
}
- 日期框添加onchange事件监听
<p:remoteCommand name="searchCommand"
process="@this,searchStartTime,searchEndTime"
update="searchStartTime,searchEndTime" />
<p:calendar pattern="yyyy-MM-dd" maxlength="10" readonlyInput="true" id="searchStartTime"
showOtherMonths="true" size="11" navigator="true"
yearRange="c-10:c+10" converterMessage="抽取日期,格式输入不正确!"
showButtonPanel="true" maxdate="#{mgrbean.searchStartMaxDate}" styleClass="myCalendar1"
value="#{mgrbean.searchStartTime}" onchange="searchCommand()" >
<p:ajax event="dateSelect" process="@this,searchStartTime,searchEndTime" update="searchEndTime" />
</p:calendar>
~
<p:calendar pattern="yyyy-MM-dd" maxlength="10" readonlyInput="true" id="searchEndTime"
showOtherMonths="true" size="11" navigator="true"
yearRange="c-10:c+10" converterMessage="抽取日期,格式输入不正确!"
showButtonPanel="true" mindate="#{mgrbean.searchEndMinDate}" maxdate="new Date()" styleClass="myCalendar1"
value="#{mgrbean.searchEndTime}" onchange="searchCommand()">
<p:ajax event="dateSelect" process="@this,searchStartTime,searchEndTime" update="searchStartTime" />
</p:calendar>
考虑到该组件用的比较多,想简化代码,在弹出日期框时刷新对应的元素,于是考虑在click时触发:
<p:remoteCommand name="searchCommand"
process="@this,searchStartTime,searchEndTime"
update="searchStartTime,searchEndTime" />
<p:calendar pattern="yyyy-MM-dd" maxlength="10" readonlyInput="true" id="searchStartTime"
showOtherMonths="true" size="11" navigator="true"
yearRange="c-10:c+10" converterMessage="抽取日期,格式输入不正确!"
showButtonPanel="true" maxdate="#{mgrbean.searchStartMaxDate}" styleClass="myCalendar1"
value="#{mgrbean.searchStartTime}" onclick="searchCommand()" >
</p:calendar>
~
<p:calendar pattern="yyyy-MM-dd" maxlength="10" readonlyInput="true" id="searchEndTime"
showOtherMonths="true" size="11" navigator="true"
yearRange="c-10:c+10" converterMessage="抽取日期,格式输入不正确!"
showButtonPanel="true" mindate="#{mgrbean.searchEndMinDate}" maxdate="new Date()" styleClass="myCalendar1"
value="#{mgrbean.searchEndTime}" onclick="searchCommand()">
</p:calendar>
实测后发现,功能全部实现,但在第一次点击日期弹出框会闪两下,分析代码后发现问题,日期input框默认绑定了focus事件,获取焦点后会调用_showDatepicker函数即显示日期选择框,然而我们这边又手动绑定了click事件,click事件分为两个动作,鼠标按下和鼠标松开,鼠标按下时,此时input框会获取焦点,触发focus,弹出一次,鼠标松开后触发click事件,又会弹出一次,于是出现了闪两次。于是将onclick事件换成onmousedown鼠标按下事件,成功解决,完整代码如下,前面的重写pluglin中的(jQuery).datepicker._attachHandlers也不需要了:
<p:remoteCommand name="searchCommand"
process="@this,searchStartTime,searchEndTime"
update="searchStartTime,searchEndTime" />
<p:calendar pattern="yyyy-MM-dd" maxlength="10" readonlyInput="true" id="searchStartTime"
showOtherMonths="true" size="11" navigator="true"
yearRange="c-10:c+10" converterMessage="抽取日期,格式输入不正确!"
showButtonPanel="true" maxdate="#{mgrbean.searchStartMaxDate}" styleClass="myCalendar1"
value="#{mgrbean.searchStartTime}" onmousedown="searchCommand()" >
</p:calendar>
~
<p:calendar pattern="yyyy-MM-dd" maxlength="10" readonlyInput="true" id="searchEndTime"
showOtherMonths="true" size="11" navigator="true"
yearRange="c-10:c+10" converterMessage="抽取日期,格式输入不正确!"
showButtonPanel="true" mindate="#{mgrbean.searchEndMinDate}" maxdate="new Date()" styleClass="myCalendar1"
value="#{mgrbean.searchEndTime}" onmousedown="searchCommand()">
</p:calendar>
将该代码组件化后,使用说明如下:
在需要开始日期和结束日期限制的地方引入下面代码
<zwx:CalendarDynamicLimitComp startDate="#{mgrbean.searchStartdate}"
endDate="#{mgrbean.searchEnddate}" defaultMaxDate="#{mgrbean.today}"/>
参数说明:
- @startDate 开始日期 必填
- @endDate 结束日期 必填
- @defaultMaxDate 默认最大日期,不必填,默认当天
- @defaultMinDate 默认最小日期,不必填
- @pattern 不必填,默认yyyy-MM-dd
- @maxlength 不必填,默认10
- @readonlyInput 不必填,默认true
- @showOtherMonths 不必填,默认true
- @size 不必填,默认11
- @navigator 不必填,默认true
- @yearRange 不必填,默认10
- @converterMessageB 不必填,默认"开始日期,格式输入不正确!"
- @converterMessageE 不必填,默认"结束日期,格式输入不正确!"
- @showButtonPanel 不必填,默认true
- @styleClass 不必填,默认myCalendar1
值得注意的是:往后台传值时需传该组件的父级,否则会出现奇怪的BUG
源码贴在下面
CalendarDynamicLimitComp.java
package customComponent;
import org.primefaces.component.calendar.Calendar;
import javax.faces.component.UINamingContainer;
import java.io.Serializable;
import java.util.Date;
/**
*
* <p>描述:日期动态限制组件</p>
*
* @MethodAuthor: 龚哲,2021/10/26 19:45,CalendarDynamicLimitComp
*/
public class CalendarDynamicLimitComp extends UINamingContainer implements Serializable {
private static final long serialVersionUID = -7618305755770492110L;
/**开始日期*/
private Calendar beginCalendar;
/**结束日期*/
private Calendar endCalendar;
private Date defaultMaxDate;
public Calendar getBeginCalendar() {
return beginCalendar;
}
public void setBeginCalendar(Calendar beginCalendar) {
this.beginCalendar = beginCalendar;
}
public Calendar getEndCalendar() {
return endCalendar;
}
public void setEndCalendar(Calendar endCalendar) {
this.endCalendar = endCalendar;
}
public Date getDefaultMaxDate() {
return new Date();
}
public void setDefaultMaxDate(Date defaultMaxDate) {
this.defaultMaxDate = defaultMaxDate;
}
}
CalendarDynamicLimitComp.xhtml
<!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:p="http://primefaces.org/ui"
xmlns:composite="http://java.sun.com/jsf/composite">
<!--日期动态限制-->
<composite:interface>
<composite:attribute name="pattern"/>
<composite:attribute name="maxlength"/>
<composite:attribute name="readonlyInput"/>
<composite:attribute name="showOtherMonths"/>
<composite:attribute name="size"/>
<composite:attribute name="navigator"/>
<composite:attribute name="yearRange"/>
<composite:attribute name="converterMessageB"/>
<composite:attribute name="converterMessageE"/>
<composite:attribute name="showButtonPanel"/>
<composite:attribute name="startDate" required="true"/>
<composite:attribute name="endDate" required="true"/>
<composite:attribute name="defaultMaxDate" />
<composite:attribute name="defaultMinDate" />
<composite:attribute name="styleClass"/>
</composite:interface>
<composite:implementation>
<p:remoteCommand name="#{cc.clientId}_searchCommand"
process="@this,bDate,eDate"
update="bDate,eDate" />
<p:calendar pattern="#{cc.attrs.pattern==null?'yyyy-MM-dd':cc.attrs.pattern}" maxlength="#{cc.attrs.maxlength==null?10:cc.attrs.maxlength}" readonlyInput="#{cc.attrs.readonlyInput==null?true:cc.attrs.readonlyInput}"
showOtherMonths="#{cc.attrs.showOtherMonths==null?true:cc.attrs.showOtherMonths}" id="bDate" size="#{cc.attrs.size==null?11:cc.attrs.size}" navigator="#{cc.attrs.navigator==null?true:cc.attrs.navigator}"
yearRange="c-#{cc.attrs.yearRange==null?10:cc.attrs.yearRange}:c+#{cc.attrs.yearRange==null?10:cc.attrs.yearRange}" converterMessage="#{cc.attrs.converterMessageB==null?'开始日期,格式输入不正确!':cc.attrs.converterMessageB}"
showButtonPanel="#{cc.attrs.showButtonPanel==null?true:cc.attrs.showButtonPanel}" styleClass="#{cc.attrs.styleClass==null?'myCalendar1':cc.attrs.styleClass}"
mindate="#{cc.attrs.defaultMinDate}" maxdate="#{cc.attrs.endDate==null?(cc.attrs.defaultMaxDate==null?cc.defaultMaxDate:cc.attrs.defaultMaxDate):cc.attrs.endDate}" value="#{cc.attrs.startDate}" binding="#{cc.beginCalendar}" onmousedown="#{cc.clientId}_searchCommand()">
</p:calendar>
~
<p:calendar pattern="#{cc.attrs.pattern==null?'yyyy-MM-dd':cc.attrs.pattern}" maxlength="#{cc.attrs.maxlength==null?10:cc.attrs.maxlength}" readonlyInput="#{cc.attrs.readonlyInput==null?true:cc.attrs.readonlyInput}"
showOtherMonths="#{cc.attrs.showOtherMonths==null?true:cc.attrs.showOtherMonths}" id="eDate" size="#{cc.attrs.size==null?11:cc.attrs.size}" navigator="#{cc.attrs.navigator==null?true:cc.attrs.navigator}"
yearRange="c-#{cc.attrs.yearRange==null?10:cc.attrs.yearRange}:c+#{cc.attrs.yearRange==null?10:cc.attrs.yearRange}" converterMessage="#{cc.attrs.converterMessageE==null?'结束日期,格式输入不正确!':cc.attrs.converterMessageE}"
showButtonPanel="#{cc.attrs.showButtonPanel==null?true:cc.attrs.showButtonPanel}" styleClass="#{cc.attrs.styleClass==null?'myCalendar1':cc.attrs.styleClass}"
mindate="#{cc.attrs.startDate==null?cc.attrs.defaultMinDate:cc.attrs.startDate}" maxdate="#{cc.attrs.defaultMaxDate==null?cc.defaultMaxDate:cc.attrs.defaultMaxDate}" value="#{cc.attrs.endDate}" binding="#{cc.endCalendar}" onmousedown="#{cc.clientId}_searchCommand()">
</p:calendar>
</composite:implementation>
</html>