[jQuery Plugin]響應式版本的日期選取器

其實市面上用jQuery Plugin撰寫的日期選取器有非常的多,但最近在開發響應式專案時,許多Plugin雖號稱有響應式的效果,但很多時候真的在小螢幕上當水平擺放多個元件時,整體的操作效果不是這麼的友善,甚至有超出畫面的狀況發生,所以決定用bootstrap的modal自幹一個日期選取器,未來有需求要延伸時也可以自己增加。

引用的檔案:

bootstrap.css
bootstrap.js
jquery.js

HTML:

<input id="myDate" value="2018/02/23" class="form-control"/>

Javascript:

$("#myDate").dataPicker({
  todayCss : "border-bottom:5px solid orange;"
});

CSS:

.data-picker-dialog .data-picker th,
.data-picker-dialog .data-picker td{
  height: 30px;
  font-size:16px;
  line-height:30px;
  text-align:center;		
}

.data-picker-dialog .data-picker td{
  cursor: pointer;				
}

/**各日期的樣式*/
.data-picker-dialog .data-picker label{
  height: 30px;
  font-size:16px;
  line-height:30px;
  width:30px;
  font-weight:normal;
  cursor:pointer;
}

/**hover各日期時的樣式*/
.data-picker-dialog .data-picker label:hover{
  background-color:orange;
  border-radius:15px;
  color:white;
}

/**Dialog框的Title樣式*/
.data-picker-dialog .modal-header {
  background-color: #6499C5;
  padding:0px;	
}

/**Dialog框的底部樣式*/
.data-picker-dialog .modal-footer{
  background-color: #6499C5;
}

JQuery Plugin:

(function ( $ ) {
  $.fn.dataPicker = function(methodOrOptions) {
    var _self = $(this);
    var settings = null;
    var methods = {
      init : function(options) {
        settings = $.extend({
          // 預設參數
          todayCss : "border-bottom:2px solid orange;"
        }, options);
    
        var tThis = $(this);
        tThis.click(function(){
          methods.show();
        });
      },
      show : function() {
        $(".data-picker-dialog").remove();

        var tSelectedDateStr = _self.val();
        var tCurrentViewYear = 1970;//目前要顯示的年份
        var tCurrentViewMonth = 1;//目前要顯示的月份

        //切一下目前的選取的日期
        if(tSelectedDateStr!=""){
          var tTmpDate = tSelectedDateStr.split("/");
          tCurrentViewYear = parseInt(tTmpDate[0]);
          tCurrentViewMonth = parseInt(tTmpDate[1]);		        	
        }else{
          var tNow = new Date();
          tCurrentViewYear = tNow.getFullYear();
          tCurrentViewMonth = tNow.getMonth()+1;
        }

        //紀錄目前查看的年月份
        _self.data("view-year", tCurrentViewYear);
        _self.data("view-month", tCurrentViewMonth);

        //開窗的Dialog HTML
        var tHtml = 
          '<div class="modal inmodal fade data-picker-dialog"  tabindex="-1" role="dialog">'+
            '<div class="modal-dialog modal-xs">'+
              '<div class="modal-content">'+
                '<div class="modal-header">'+
                  '<div class="modal-title">'+
                    '<label class="view-info" style="color:white; font-size:20px; padding:5px 0px;"><label>'+
                  '</div>'+
                '</div>'+
                '<div class="modal-body data-picker" style="text-align:center;">'+
                  '<table style="width:100%;">'+
                    '<tbody>'+
                      '<tr>'+
                        '<th class="data-picker-pre-year" style="width:15%; cursor:pointer;">'+
                          '&lt;&lt;'+
                        '</th>'+
                        '<th class="data-picker-pre-month" style="width:15%; cursor:pointer;">'+
                          '&lt;'+
                         '</th>'+
                         '<th class="data-picker-today" style="width:40%; cursor:pointer;">'+
                           'Today'+
                         '</th>'+
                         '<th class="data-picker-next-month" style="width:15%; cursor:pointer;">'+
                           '&gt;'+
                         '</th>'+
                         '<th class="data-picker-next-year" style="width:15%; cursor:pointer;">'+
                           '&gt;&gt;'+
                         '</th>'+
                       '</tr>'+
                    '</tbody>'+
                  '</table>'+
                  '<table style="width:100%;">'+
                    '<thead>'+
                      '<tr>'+
                        '<th style="font-weight:normal;">Sun</th>'+
                        '<th style="font-weight:normal;">Mon</th>'+
                        '<th style="font-weight:normal;">Tue</th>'+
                        '<th style="font-weight:normal;">WED</th>'+
                        '<th style="font-weight:normal;">THU</th>'+
                        '<th style="font-weight:normal;">Fri</th>'+
                        '<th style="font-weight:normal;">SAT</th>'+
                      '</tr>'+
                    '</thead>'+
                    '<tbody class="data-picker-content">'+
                    '</tbody>'+
                  '</table>'+
                '</div>'+
                '<div class="modal-footer">'+
                '</div>'+
              '</div>'+
            '</div>'+
          '</div>';
        var tDataPicker = $(tHtml);
        $("body").append(tDataPicker);

        //塞入當月的所有日期
        methods._genDateContent(tDataPicker);

        //前一個月
        tDataPicker.find(".data-picker-pre-month").click(function(){
          var tCurrentViewYear = _self.data("view-year");
          var tCurrentViewMonth = _self.data("view-month");							
          var tViewDate = new Date(tCurrentViewYear,(tCurrentViewMonth-2),1);
          _self.data("view-year", tViewDate.getFullYear());
          _self.data("view-month", tViewDate.getMonth()+1);
          methods._genDateContent(tDataPicker);
        });

        //後一個月
        tDataPicker.find(".data-picker-next-month").click(function(){
          var tCurrentViewYear = _self.data("view-year");
          var tCurrentViewMonth = _self.data("view-month");							
          var tViewDate = new Date(tCurrentViewYear,(tCurrentViewMonth+1),1);
          _self.data("view-year", tViewDate.getFullYear());
          _self.data("view-month", tViewDate.getMonth());
          methods._genDateContent(tDataPicker);
        });

        //前一年
        tDataPicker.find(".data-picker-pre-year").click(function(){
          var tCurrentViewYear = _self.data("view-year")-1;
          var tCurrentViewMonth = _self.data("view-month");							
          var tViewDate = new Date(tCurrentViewYear,(tCurrentViewMonth-1),1);
          _self.data("view-year", tViewDate.getFullYear());
          _self.data("view-month", tViewDate.getMonth()+1);
          methods._genDateContent(tDataPicker);
        });

        //後一年
        tDataPicker.find(".data-picker-next-year").click(function(){
          var tCurrentViewYear = _self.data("view-year")+1;
          var tCurrentViewMonth = _self.data("view-month");							
          var tViewDate = new Date(tCurrentViewYear,(tCurrentViewMonth-1),1);
          _self.data("view-year", tViewDate.getFullYear());
          _self.data("view-month", tViewDate.getMonth()+1);
	      methods._genDateContent(tDataPicker);
        });

        //這個月
        tDataPicker.find(".data-picker-today").click(function(){			        		
          var tToday = new Date();			        		
          _self.data("view-year", tToday.getFullYear());
          _self.data("view-month", tToday.getMonth()+1);
	      methods._genDateContent(tDataPicker);
        });

        $(".data-picker-dialog").modal("toggle");
      },
      _genDateContent : function(tDataPicker) {		
        var tDataPickerContent = tDataPicker.find(".data-picker-content");
        tDataPickerContent.empty();

        //目前要產生的年月份
        var tCurrentViewYear = _self.data("view-year");
        var tCurrentViewMonth = _self.data("view-month");

        //塞入標題
        tDataPicker.find(".view-info").html(tCurrentViewYear+",&nbsp;&nbsp;"+tCurrentViewMonth+"M");

        var tToday = new Date();

        var tDateHtml = "";				        	
        //取得該月份的第一天是星期幾
        //星期日 = 0, 星期一 = 1, 星期二 = 2, 星期三 = 3, 星期四 = 4,星期五 = 5, 星期六 = 6
        var tDay = new Date(tCurrentViewYear,(tCurrentViewMonth-1),1).getDay();

        //補足第一行的空格
        for(var i=0;i<tDay;i++){
          tDateHtml = tDateHtml + '<td></td>';
        }

        //取得該月份有幾天
        var tDays =  new Date(tCurrentViewYear,(tCurrentViewMonth),0).getDate();
        for(var i=1;i<=tDays;i++){
          var tdSize = tDateHtml.split("<td>").length;
          if((tdSize-1)%7 == 0){
            tDateHtml = tDateHtml + "●";
          }

          var tStyle = "";
          if(tToday.getFullYear() == tCurrentViewYear && (tToday.getMonth()+1) == tCurrentViewMonth && i == tToday.getDate()){
            //如果是今天的話該日期的CSS
            tStyle = settings.todayCss;
          }

          tDateHtml = tDateHtml + 
            '<td>'+
              '<label style="'+tStyle+'">'+
                i+
              '</label>'+
            '</td>';
        }

        tDateHtml = tDateHtml.replace(/●/g, "</tr><tr>");
        tDateHtml = "<tr>" + tDateHtml + "</tr>";
        tDataPickerContent.append(tDateHtml);

        //註冊每一個日期的點擊事件
        tDataPicker.find("label").click(function(){

          //選到的月
          var tSelectedMonth = tCurrentViewMonth;
          if(tSelectedMonth<=9){
            tSelectedMonth = "0"+tSelectedMonth;
          }

          //選到的日
          var tSelectedDate = $(this).html();
          if(parseInt(tSelectedDate)<=9){
            tSelectedDate = "0"+tSelectedDate;
          }

          //將選到的日期塞到欄位中
          _self.val(tCurrentViewYear+"/"+ tSelectedMonth +"/"+ tSelectedDate);

          //關閉此Dialog
          $(".data-picker-dialog").modal("toggle");
        });
      }
    };

    if ( methods[methodOrOptions] ) {
      return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  methodOrOptions + ' does not exist on jQuery.dataPicker' );
    }    
  };
}(jQuery));