PrimeFaces日期限制框优化

本文介绍了如何在PrimeFaces的日期选择器上实现开始日期选择时动态调整结束日期范围,以及解决清空日期时的事件触发问题。通过重写插件和绑定onmousedown事件,确保了日期限制功能的完善和用户体验的提升。
摘要由CSDN通过智能技术生成

在看之前项目的代码中发现,查询条件中的日期限制(即开始日期和结束日期)是在后台加以验证的,至于前台无任何限制,表现效果如下:



现可以将效果优化显示如下:

核心逻辑:选择开始日期时动态改变结束日期的最小日期,选择结束日期时动态改变开始日期的最大日期
核心代码:
<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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值