【问题标题】:Date range picker on jquery ui datepickerjquery ui datepicker上的日期范围选择器
【发布时间】:2013-04-18 20:18:47
【问题描述】:

我使用 jquery ui 创建了一个日期范围选择器,您可以在其中使用相同的内联日历来进行两个日期选择。

在这里看我的小提琴:http://jsfiddle.net/kVsbq/4/

JS

$(".datepicker").datepicker({
    minDate: 0,
    numberOfMonths: [12, 1],
    beforeShowDay: function (date) {
        var date1 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input1").val());
        var date2 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input2").val());
        return [true, date1 && ((date.getTime() == date1.getTime()) || (date2 && date >= date1 && date <= date2)) ? "dp-highlight" : ""];
    },
    onSelect: function (dateText, inst) {
        var date1 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input1").val());
        var date2 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input2").val());
        if (!date1 || date2) {
            $("#input1").val(dateText);
            $("#input2").val("");
            $(this).datepicker();
        } else {
            $("#input2").val(dateText);
            $(this).datepicker();
        }
    }
});

我想做的是这样的范围选择器:http://jsfiddle.net/D3wLX/1/

如果您选择较早的日期,则较早的日期会自动成为范围内的第一个日期,中间日期会突出显示。现在在我原来的 jquery ui 解决方案中,它只会将较早的日期放在第二个输入中,而不是突出显示两者之间的日期。

【问题讨论】:

    标签: javascript jquery jquery-ui jquery-ui-datepicker date-range


    【解决方案1】:

    你的剧本正是我要找的。我分叉了你原来的小提琴,只对你的 onSelect 做了轻微的调整,让它按照你想要的方式工作。

    onSelect: function(dateText, inst) {
        var date1 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input1").val());
        var date2 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input2").val());
        var selectedDate = $.datepicker.parseDate($.datepicker._defaults.dateFormat, dateText);
    
    
        if (!date1 || date2) {
            $("#input1").val(dateText);
            $("#input2").val("");
            $(this).datepicker();
        } else if( selectedDate < date1 ) {
            $("#input2").val( $("#input1").val() );
            $("#input1").val( dateText );
            $(this).datepicker();
        } else {
            $("#input2").val(dateText);
            $(this).datepicker();
        }
    }
    

    原始部分中缺少的只是将当前选定的日期值与已捕获的日期值进行比较的检查。

    这是我的分叉小提琴: http://jsfiddle.net/sWbfk/

    【讨论】:

    • 好的,这是一个很棒的解决方案。我有一个问题,因为我试图完全理解它是如何/为什么起作用的。 onSelect 将成为标记选定日期的方法是有道理的。对我来说没有意义的是为什么 beforeShowDay 有实际上将突出显示类添加到日期的行。我认为 beforeShowDay 是在构建日历时调用的,在显示每一天之前。我在构建我的 12 个月日历时使用它来突出显示预订的日期(我已将这些合并到操作中)。那么,当你选择(onSelect)一个日期时,它是如何再次调用的呢?谢谢,汤姆
    【解决方案2】:

    我在这里找到了答案:

    http://www.benknowscode.com/2012/11/selecting-ranges-jquery-ui-datepicker.html(该网站似乎已被黑客入侵)

    很棒的教程

    $.datepicker._defaults.onAfterUpdate = null;
    var datepicker__updateDatepicker = $.datepicker._updateDatepicker;
    $.datepicker._updateDatepicker = function( inst ) {
       datepicker__updateDatepicker.call( this, inst );
       var onAfterUpdate = this._get(inst, 'onAfterUpdate');
       if (onAfterUpdate)
          onAfterUpdate.apply((inst.input ? inst.input[0] : null),
             [(inst.input ? inst.input.val() : ''), inst]);
    }
    $(function() {
       var cur = -1, prv = -1;
       $('#jrange div')
          .datepicker({
                //numberOfMonths: 3,
                changeMonth: true,
                changeYear: true,
                showButtonPanel: true,
                beforeShowDay: function ( date ) {
                      return [true, ( (date.getTime() >= Math.min(prv, cur) && date.getTime() <= Math.max(prv, cur)) ? 'date-range-selected' : '')];
                   },
                onSelect: function ( dateText, inst ) {
                      var d1, d2;
                      prv = cur;
                      cur = (new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay)).getTime();
                      if ( prv == -1 || prv == cur ) {
                         prv = cur;
                         $('#jrange input').val( dateText );
                      } else {
                         d1 = $.datepicker.formatDate( 'mm/dd/yy', new Date(Math.min(prv,cur)), {} );
                         d2 = $.datepicker.formatDate( 'mm/dd/yy', new Date(Math.max(prv,cur)), {} );
                         $('#jrange input').val( d1+' - '+d2 );
                      }
                   },
                onChangeMonthYear: function ( year, month, inst ) {
                      //prv = cur = -1;
                   },
                onAfterUpdate: function ( inst ) {
                      $('<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" data-handler="hide" data-event="click">Done</button>')
                         .appendTo($('#jrange div .ui-datepicker-buttonpane'))
                         .on('click', function () { $('#jrange div').hide(); });
                   }
             })
          .position({
                my: 'left top',
                at: 'left bottom',
                of: $('#jrange input')
             })
          .hide();
       $('#jrange input').on('focus', function (e) {
             var v = this.value,
                 d;
             try {
                if ( v.indexOf(' - ') > -1 ) {
                   d = v.split(' - ');
                   prv = $.datepicker.parseDate( 'mm/dd/yy', d[0] ).getTime();
                   cur = $.datepicker.parseDate( 'mm/dd/yy', d[1] ).getTime();
                } else if ( v.length > 0 ) {
                   prv = cur = $.datepicker.parseDate( 'mm/dd/yy', v ).getTime();
                }
             } catch ( e ) {
                cur = prv = -1;
             }
             if ( cur > -1 )
                $('#jrange div').datepicker('setDate', new Date(cur));
             $('#jrange div').datepicker('refresh').show();
          });
    });
    .wrapper {
       height: 600px;
    }
    #jrange input {
       width: 200px;
    }
    #jrange div {
       font-size: 9pt;
    }
    .date-range-selected > .ui-state-active,
    .date-range-selected > .ui-state-default {
       background: none;
       background-color: lightsteelblue;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
    <div class="wrapper">
       <div id="jrange" class="dates">
        <input />
        <div></div>
       </div>
    </div>

    【讨论】:

    • 链接已关闭,不再可用。
    • 链接中的图片都损坏了……这个网络开发者需要更新他们的网站。
    【解决方案3】:

    我也在寻找一种方法来扩展 Datepicker jQuery 插件以利用 Bootstrap 样式并遇到了这个小宝石:

    Bootstrap-Date Range Picker by Dan Grossman 展示了一些带有工作代码的实时示例。

    这里也是GitHub 的项目。

    最后,这里是一个简单和强大的设计截图:

    【讨论】:

      【解决方案4】:

      老兄,你的代码正是我需要的!

      在 Jamie Layne 的修正下,我决定用它来制作插件。

      这里是 jsfiddle 的链接:http://jsfiddle.net/dxLRm/35/(链接更新于 2014/01/01)

      由于我必须显示一些代码,所以我有以下内容:

      (function ($) {
      $.prototype.rangedatepicker = function (o,x,y) {
          var dp = $.datepicker,
              cl = dp.markerClassName,
              di = 'data-rdp-i',
              df = 'data-rdp-f';
      
          switch(o)
          {
              case 'option':
                  return $(this).datepicker('option');
              case 'hide':
                  return $(this).datepicker('hide');
              case 'show':
                  return $(this).datepicker('show');
              case 'getInitialDate':
                  return dp.parseDate($(this).eq(0).datepicker('option','dateFormat'),$(this).eq(0).attr(di)||'');
              case 'getFinalDate':
                  return dp.parseDate($(this).eq(0).datepicker('option','dateFormat'),$(this).eq(0).attr(df)||'');
              case 'getRange':
                  var ini=dp.parseDate($(this).eq(0).datepicker('option','dateFormat'),$(this).eq(0).attr(di)||''),
                      fin=dp.parseDate($(this).eq(0).datepicker('option','dateFormat'),$(this).eq(0).attr(df)||'');
                  return (!ini&&!fin)?null:[ini,fin];
              case 'getNumDays':
                  var ini=dp.parseDate($(this).eq(0).datepicker('option','dateFormat'),$(this).eq(0).attr(di)||''),
                      fin=dp.parseDate($(this).eq(0).datepicker('option','dateFormat'),$(this).eq(0).attr(df)||'');
                  return (ini+0==0||fin+0==0)?0:Math.round((fin-ini)/86400000)+1;
              case 'removeRange':
                  return $(this).attr(di,'').attr(df,'').datepicker('setDate',null);
              case 'destroy':
                  return $(this).removeAttr(di).removeAttr(df).datepicker('destroy');
              case 'serialize':
                  return this[0].id+'_initial='+this[0].getAttribute(di)+'&'+this[0].id+'_final='+this[0].getAttribute(df);
              default:
              var defaults={
                  allowSelectOneDay: false,
                  alwaysSetDateToFirstDay: true,
                  rangeEnabled: true,
                  rangeClass: 'ui-state-default ui-state-active'//'dp-highlight'
              };
                  o = $.extend({}, defaults, $.datepicker._defaults, o);
              return $(this).each(function () {
                  if (!$.datepicker) return;
                  var t = this,
                      hd = !! ((' ' + t.className + ' ').indexOf(' ' + cl + ' ') + 1);
                  $(t).datepicker($.extend({}, o, {
                      beforeShowDay: function (d) {
                          if (o.rangeEnabled) {
                              var d1 = dp.parseDate(o.dateFormat, t.getAttribute(di) || ''),
                                  d2 = dp.parseDate(o.dateFormat, t.getAttribute(df) || ''),
                                  y = (function (d) {
                                      try {
                                          return o.beforeShowDay.call(t, d);
                                      } catch (e) {}
                                  })(d) || [true, '', null],
                                  x = ((y && y[0] !== false) || !y) && d1 && ((d.getTime() == d1.getTime()) || (d2 && d >= d1 && d <= d2));
                              return (!d1||!d2)?y||[true,'',null]:[y[0]&&x, (x ? o.rangeClass || defaults.rangeClass : '') + (y[1] ? ' ' + y[1] : ''), y[2]];
                          } else {
                              return (function (d) {
                                  try {
                                      return o.beforeShowDay.call(t, d);
                                  } catch (e) {}
                              })(d) || [true, '', null];
                          }
                      },
                      onSelect: function (dt, x) {
                          if (o.rangeEnabled) {
                              var i = t.getAttribute(di) || '',
                                  f = t.getAttribute(df) || '',
                                  d1 = dp.parseDate(o.dateFormat, i),
                                  d2 = dp.parseDate(o.dateFormat, f),
                                  s = dp.parseDate(o.dateFormat, dt);
                              if ((dt == i && dt == f) || (!o.allowSelectOneDay && ((dt == i && !f) || (dt == f && !i)))) {
                                  t.removeAttribute(di);
                                  t.removeAttribute(df);
                                  $(t).datepicker('setDate', null);
                              } else if (!d1 || d2) {
                                  t.setAttribute(di, dt);
                                  t.removeAttribute(df);
                                  o.alwaysSetDateToFirstDay && $(t).datepicker('setDate', s);
                              } else if (s < d1) {
                                  t.setAttribute(df, i);
                                  t.setAttribute(di, dt);
                                  o.alwaysSetDateToFirstDay && $(t).datepicker('setDate', s);
                              } else {
                                  t.setAttribute(df, dt);
                                  o.alwaysSetDateToFirstDay && $(t).datepicker('setDate', d1);
                              }
                          } else {
                              t.removeAttribute(di);
                              t.removeAttribute(df);
                              $(t).datepicker('setDate', dp.parseDate(o.dateFormat, dt));
                          }
      
                          try {
                              if($(t).datepicker('getDate'))o.onSelect.call(t, dt, x);
                          } catch (e) {}
                      }
                  }));
              });
          }
      };
      })(window.jQuery);
      

      您应该访问小提琴并阅读要做的事情列表!

      感谢任何想法或代码!

      【讨论】:

        【解决方案5】:

        谢谢,我需要这种代码。这是我的代码:

        <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
        <link rel="stylesheet" href="/resources/demos/style.css">
        <script     src="https://code.jquery.com/jquery-1.12.4.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
        
         <div id="Datepicker"></div>
        <p>
        <label><b>Checkin:</b></label> <label id="checkinDate"></label>
        <label><b>Checkout:</b></label> <label id="checkoutDate"></label>
        </p>
        
        /** Display Checkin Datepicker and Checkout DatePicker */
        <script>
        datePicker();
        function datePicker(){
           $(document).ready(function(){
              $( "#Datepicker" ).datepicker({
                 dateFormat: "MM d, yy",
             minDate: 0,
             maxDate: "+3M +0D", 
                 beforeShowDay: dateRange,
             onSelect: DRonSelect
              });
           });
        }
        
        function dateRange(date){
           var date1 = $.datepicker.parseDate("MM d, yy", $("#checkinDate").text());
           var date2 = $.datepicker.parseDate("MM d, yy", $("#checkoutDate").text());
           var isHighlight = date1 && ((date.getTime() == date1.getTime()) || (date2 && date >= date1 && date <= date2));
              $(document).ready(function(){
          // $("td.dp-highlight").text("Y");
        
        });
           return [true, isHighlight ? "dp-highlight" : ""];
        }
        
        function DRonSelect(dateText, inst) {
           var date1 = $.datepicker.parseDate("MM d, yy", $("#checkinDate").text());
           var date2 = $.datepicker.parseDate("MM d, yy", $("#checkoutDate").text());
              if (!date1 || date2) {
                 $("#checkinDate").text(dateText);
             $("#checkoutDate").text("");
                 $("#Datepicker").datepicker();
              } 
              else {
                 if ( $.datepicker.parseDate("MM d, yy", $("#checkinDate").text()) >= 
        $.datepicker.parseDate("MM d, yy", dateText)) {
                    $("#checkinDate").text(dateText);
                    $("#checkoutDate").text("");
                    $("#Datepicker").datepicker();
                 }
                 else {
                $("#checkoutDate").text(dateText);
                    $("#Datepicker").datepicker();
                 }
              }   
        }
        </script>
        

        我的代码是来自其他代码的示例代码,但在日期选择、日期范围和亮点方面有所不同。我在 JSFIDDLE 中创建并保存了一个代码

        https://jsfiddle.net/kk585b4g/

        【讨论】:

        • 你可以给出更多的理由,为什么你改变了一些部分。另一种方式,复制其他答案很简单。
        • 嗨蒂米陶。这里的所有人都很友善,他们共享代码并在此处发布代码。我更改了一些部分,因为我喜欢我修改的 datepicker 的结果。我也不能给出更多的理由,因为我只需要分享代码/脚本之类的帮助。我希望你的代码也可以通过分享代码来帮助我。
        【解决方案6】:

        我自己寻找一个日期范围选择器,我找到了这个页面。我尝试了大多数建议甚至在这里演示的想法,并将这一切变成了一个易于使用和集成的扩展:https://github.com/BuroRaDer/DateRangePicker。试试演示页面看看它是如何工作的。我想我可以把它变成一个真正的 jQuery 扩展,但现在对它的工作方式很满意。

        现场演示:

        两者都是 Drupal 站点,使用现在已集成的可用性日历模块。

        【讨论】:

        • 您为什么要创建不同的帐户来一遍又一遍地发布相同的答案?你在这篇文章中发布了与@Charu 完全相同的答案
        • @NSNoob 的评论已过时(首先是不正确的),请删除。
        【解决方案7】:

        我一直在寻找一个即使没有内联也能工作的版本。我希望能够单击输入字段来启动范围日期选择器。我能找到的所有范围日期选择器示例都是内联的(包括上面的 mcestone 和 Jamie Layne 版本,它们是这个分叉代码的基础)。

        这是小提琴:http://jsfiddle.net/boson/pjffdtz2/

        困难的部分似乎是让日期选择器在未内联时处理多个输入。如果您想在焦点上打开日期选择器,日期选择器将无法轻松处理两个输入 - 肯定有一个“技巧”。如果您将日期选择器与隐藏输入(显示:无)相关联,请在可见输入之前创建该隐藏输入,然后让您的可见输入在点击事件上显示日期选择器,一切都很好。

        所以我接受了原来的答案,只是做了一些小改动:

        • 在 html 中,创建一个与日期选择器关联的隐藏输入。将其列在可见输入之前。
        • 在 html 中,使用可见输入的点击事件来显示与隐藏输入关联的日期选择器。
        • 在 Javascript 日期选择器 onSelect 中,暂时将日期选择器置于内联模式,直到两个日期都被单击。这允许您在 datepicker 关闭之前单击多个日期(范围“To”日期和“From”日期) - 这实际上将 datepicker 变成了一个多击 datepicker。
        • 在关闭日期选择器中,关闭内联模式。这允许某人单击输入字段以再次打开日期选择器。
        • 在 beforeShow 中,将日期选择器向下移动几个像素,以便您可以看到输入字段和日期选择器

        代码如下:

        $(function() {
          $(".rangepicker").datepicker({
            minDate: 0,
            numberOfMonths: [2, 1],
            beforeShow: function (input, inst) {
              var rect = input.getBoundingClientRect();
              setTimeout(function () {
        	      inst.dpDiv.css({ top: rect.top + 40, left: rect.left + 0 });
              }, 0);
            },
            beforeShowDay: function(date) {
              var date1 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input1").val());
              var date2 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input2").val());
              var isHighlight =
                 date1 && ((date.getTime() == date1.getTime()) || (date2 && date >= date1 && date <= date2));
              return [true, isHighlight ? "dp-highlight" : ""];
            },
            onSelect: function(dateText, inst) {
              var date1 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input1").val());
              var date2 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input2").val());
              var selectedDate = $.datepicker.parseDate($.datepicker._defaults.dateFormat, dateText);
        
              if (!date1 || date2) {
                $("#input1").val(dateText);  
                $("#input2").val("");        
              } else if (selectedDate < date1) {
                  $("#input2").val($("#input1").val()); 
                  $("#input1").val(dateText);  
              } else {
                  $("#input2").val(dateText);  
              }
              $(this).data('datepicker').inline = true;           
              $(this).datepicker();
            },
            onClose: function() {
              // Since we went inline as soon as the date input was clicked
              // (to leave the datepicker up for both dates selection),
              // turn inline back off again so date input click will once again
              // display the datepicker
              $(this).data('datepicker').inline = false;
            }
          });
        });
        .dp-highlight .ui-state-default {
                  background: #484;
                  color: #FFF;
                }
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
        <input type="text" id="input1_1" class="rangepicker" style="display: none">
        <p>
            Dates:
            <label><b>To:</b></label>
            <input type="text" id="input1" onclick="$('.rangepicker').datepicker('show');">
            <label><b>From:</b></label>
            <input type="text" id="input2" onclick="$('.rangepicker').datepicker('show');">
            <button id="done">Done</button>
        </p>

        还有很多需要改进的地方。需要更好的输入验证。特别希望让日期选择器的“完成”按钮在内联模式下工作,但日期选择器不是为这种情况设计的(当然,在日期选择器中有一个可设置的完成按钮标志会很好)。所以现在,我在输入字段旁边有一个俗气的完成按钮,实际上什么都不做(除了鼓励用户将焦点从日期选择器上移开以关闭日期选择器)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-19
          • 1970-01-01
          • 2014-11-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多