jQueryUI Datepicker

jQuery UI Datepicker改造大作戰

廖汶彬 2016/10/24 11:00:00
3162

主題

jQuery UI Datepicker改造大作戰

文章簡介

利用jQuery UI Datepicker現有的功能進行改造。讓日曆選單可跨月顯示選取日期範圍區間,並隱藏其他不可選擇之日期。

作者

廖汶彬

版本

1.0

產出日期

2016.10.21



某天有個朋友兼同事跟我許了一個願望

網頁想要一個日期選擇器

"只要"顯示包含今天在內的當週,以及後續4周

也就是只能選取特定區間的日期


我馬上就聯想到jQuery UI的Datepicker"應該"能夠符合這樣的需要

jQuery UI Datepicker可透過設定定義可選取的日期區間


jQuery UI Datepicker Restrict the range程式碼

$( "#datepicker" ).datepicker({

    minDate: 0,

    maxDate: 28

});


Restrict the range

CodePen-jQueryUI Datepicker Restrict the range


但是事情沒有我想的這麼容易

針對畫面呈現的部份還希望可以選取的日期以外的日期通通不要出現在日曆選單上

並且當日期區間未跨月則顯示1個月的日曆選單

如果跨月時要一次顯示2個月的日曆選單


由於需要去異動日曆選單的介面

所以需要在日曆選單顯示後增加程式碼去調整介面

但是jQuery UI Datepicker沒有提供這樣的事件可以使用

第一個要解決的問題是Datepicker並沒有日曆選單顯示後的事件


增加jQuery UI Datepicker日曆選單顯示後的事件(afterShow)

$.datepicker._updateDatepicker_original = $.datepicker._updateDatepicker;

$.datepicker._updateDatepicker = function(inst) {

$.datepicker._updateDatepicker_original(inst);

var afterShow = this._get(inst, 'afterShow');

if (afterShow)

afterShow.apply((inst.input ? inst.input[0] : null));

};


增加上述的程式碼之後即可在datapicker綁定時增加 afterShow 的事件設定

此外跨月時要要顯示2個月的日曆選單則可透過原本Datepicker的設定達成

numberOfMonths屬性資料類型為Number


一次顯示2個月的日曆屬性 numberOfMonths

.ui-datepicker-multi .ui-datepicker-group{

clear:both;

width:100%;

}


考慮到程式的共用性我設計了一個function用來綁定jQuery UI Datepicker

以現在的日期做基準加上minDiffDay做為可選取日期範圍的最小日期

加上maxOffsetDay做為可選取日期範圍的最大日期

並將jQuery UI Datepicker綁定至datepickerObject

function需提供3個參數

minDiffDay:設定可選取日期範圍最小日期(單位為天,可為正負整數)

maxOffsetDay:設定可選取日期範圍最大日期(單位為天,可為正負整數)

datepickerObject:綁定目標(jQuery object)


為了方便計算日期引用了強大的時間處理的函式庫 Moment.js

計算日期區間跨了幾個月份可使用來設定numberOfMonths屬性


由於一次會顯示所有可選擇的日期區間所以就把切換月份的按鈕隱藏

屬性為hideIfNoPrevNext設定為true


設定afterShow的事件應執行的function對日曆選單的介面進行調整即可完成設定


綁定jQuery UI Datepicker的function

function RangeDatePickerBind(minDiffDay,maxOffsetDay,datepickerObject){

var minDay = new moment().add(minDiffDay, 'days');

var maxDay = new moment().add(maxOffsetDay, 'days');

var displayMonth=maxDay.month()-minDay.month()+1;

datepickerObject.datepicker({

dateFormat: "yy-mm-dd",

minDate: minDiffDay,

maxDate: maxOffsetDay,

numberOfMonths: displayMonth,

hideIfNoPrevNext: true,

afterShow:function(){

//判斷是否有自訂樣式 讓日曆選單垂直排列

if($(".ui-datepicker-multi .ui-datepicker-group").css("clear") === "both"){

$("#ui-datepicker-div").css("width",$("#ui-datepicker-div").width()/displayMonth);

}

//隱藏第一個月份可選取日期前的所有日期

$("#ui-datepicker-div .ui-datepicker-calendar:first").find("td[data-handler='selectDay']:first")

    .prevAll("td").css("visibility","hidden");

$("#ui-datepicker-div .ui-datepicker-calendar:first").find("td[data-handler='selectDay']:first")

    .parent("tr").prevAll("tr").find("td").hide();

//隱藏最後一個月份可選取日期後的所有日期

$("#ui-datepicker-div .ui-datepicker-calendar:last").find("td[data-handler='selectDay']:last")

    .nextAll("td").hide();

$("#ui-datepicker-div .ui-datepicker-calendar:last").find("td[data-handler='selectDay']:last")

    .parent("tr").nextAll("tr").find("td").hide();

}

});

}


依據需要的日期範圍與綁定目標設定完畢

即可套用這個客製化的Datepicker

使用方式

$(function() {

RangeDatePickerBind(-7,7,$("#datepicker_1"));

RangeDatePickerBind(0,28,$("#datepicker_2"));

});


CodePen-客製 Datepicker完整程式碼範例


以上是我改造Datepicker的過程與想法

提供給大家參考

廖汶彬