jquery ui datepicker上的日期范围选择器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16092288/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 16:25:17  来源:igfitidea点击:

Date range picker on jquery ui datepicker

javascriptjqueryjquery-uijquery-ui-datepickerdate-range

提问by Mcestone

I created a date range picker using jquery ui where you can use the same inline calendar to make both of your date selections.

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

See my fiddle here: http://jsfiddle.net/kVsbq/4/

在此处查看我的小提琴:http: //jsfiddle.net/kVsbq/4/

JS

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();
        }
    }
});

What I want to be able to do is a range selector like this: http://jsfiddle.net/D3wLX/1/

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

If you select an earlier date then the earlier date is automatically made the first date in the range and the middle dates are highlighted. Right now on my original jquery ui solution it will just put the earlier date in the second input and not highlight the dates in between.

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

采纳答案by Mcestone

I found the answer here:

我在这里找到了答案:

http://www.benknowscode.com/2012/11/selecting-ranges-jquery-ui-datepicker.html(the site looks to have been hacked)

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

Great tutorial

很棒的教程

$.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>

回答by Jamie Layne

Your script was exactly what I was looking for. I forked your original fiddle and made only a slight adjustment to your onSelect to get it to work the way that you wanted.

你的剧本正是我要找的。我分叉了你原来的小提琴,只对你的 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();
    }
}

What was missing from your original section was simply a check to compare the current selected date value to the one that was already captured.

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

Here is my forked fiddle: http://jsfiddle.net/sWbfk/

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

回答by Blairg23

I was also looking for a way to extend the Datepicker jQuery plugin to utilize Bootstrap styling and came across this little gem:

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

Bootstrap-Date Range Pickerby Dan Grossman shows some live examples with working code.

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

Here is the project GitHubas well.

这里也是GitHub项目。

Finally, here is a screenshot of the simplicity and power of the design:

最后,这是设计的简单性和强大功能的屏幕截图:

screenshot

截屏

回答by Marvin

Thanks I need this kind of code. Here is my code:

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

<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>

My code is a sample code come from the others but differs in date selection, date range and higlights. I created and save a code in JSFIDDLE

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

https://jsfiddle.net/kk585b4g/

https://jsfiddle.net/kk585b4g/

回答by Ismael Miguel

Dude, your code is really what I needed!

伙计,你的代码正是我所需要的!

And with Jamie Layne's correction, I decided to use it to make a plugin.

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

Here is the link for jsfiddle: http://jsfiddle.net/dxLRm/35/(link updated 2014/01/01)

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

Since I have to show some code, here is what I have:

由于我必须显示一些代码,这是我所拥有的:

(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);

You should access the fiddle and read the list of things to do!

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

Any idea or piece of code is appreciated!

任何想法或一段代码表示赞赏!

回答by fietserwin

Looking for a date range picker myself, I found this page. I tried most ideas suggested and even demonstrated here and turned this all into an easy to use and integrate extension: https://github.com/BuroRaDer/DateRangePicker. Try the demo page to see how it works. I guess I could turn it into a real jQuery extension, but for now am happy with the way it works.

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

Live demos:

现场演示:

Both are Drupal sites using the Availability Calendar module into which it has been integrated now.

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

回答by boson

I was looking for a version that would work even when it is not inlined. I wanted to be able to click on the input fields to fire up the range datepicker. All the range datepicker examples I could find were inlined (including the mcestone and Jamie Layne versions above, which are the basis for this forked code).

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

Here's the fiddle: http://jsfiddle.net/boson/pjffdtz2/

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

The hard part seems to be getting datepicker to handle multiple inputs when not inlined. Datepicker won't handle two inputs easily if you want to open datepicker on focus - there was definitely a 'trick'. If you associate the datepicker with a hidden input (display:none), create that hidden input before the visible inputs, then have your visible inputs show the datepicker on a click event, all is good.

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

So I took the original answer and just made a few minor changes:

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

  • In html, create a hidden input associated with the datepicker. List it beforethe visible inputs.
  • In html, use the click event of the visible inputs to show the datepicker associated with the hidden input.
  • Within the Javascript datepicker onSelect, temporarily put the datepicker in inline mode until both dates have been clicked. This allows you to click on multiple dates before datepicker closes (the range 'To' date and 'From' date) - this essentially turns datepicker into a multiclick datepicker.
  • In the datepicker onClose, turn off inline mode. This allows someone to click on the input fields to open datepicker again.
  • In beforeShow, move the datepicker down a few pixels so you can see the input fields and the datepicker
  • 在 html 中,创建一个与日期选择器关联的隐藏输入。在可见输入之前列出它。
  • 在 html 中,使用可见输入的 click 事件来显示与隐藏输入关联的日期选择器。
  • 在 Javascript datepicker onSelect 中,临时将 datepicker 置于内联模式,直到单击两个日期。这允许您在 datepicker 关闭之前单击多个日期(范围“To”日期和“From”日期) - 这实际上将 datepicker 变成了多单击 datepicker。
  • 在日期选择器 onClose 中,关闭内联模式。这允许某人单击输入字段以再次打开日期选择器。
  • 在 beforeShow 中,将日期选择器向下移动几个像素,以便您可以看到输入字段和日期选择器

Here's the code:

这是代码:

$(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>

Lots of things left to improve. Needs better input validation. Especially would like to get the datepicker 'Done' button to work in inline mode but datepicker wasn't designed for this scenario (sure would be nice to have a settable Done button flag in datepicker). So for now, I have a cheesy done button alongside the input fields that actually does nothing (other than encouraging the user to take the focus off the datepicker to close the datepicker).

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