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

时间:2013-04-18 20:18:48

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

我使用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解决方案中,它只会将较早的日期放在第二个输入中,而不是突出显示两者之间的日期。

7 个答案:

答案 0 :(得分:17)

你的脚本正是我想要的。我分叉你原来的小提琴,只对你的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/

答案 1 :(得分:7)

我在这里找到了答案:

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>

答案 2 :(得分:1)

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

随着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);

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

感谢任何想法或代码!

答案 3 :(得分:1)

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

Dan Grossman的

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

这也是项目GitHub

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

screenshot

答案 4 :(得分:1)

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

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

答案 5 :(得分:0)

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

现场演示:

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

答案 6 :(得分:0)

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

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

当没有内联时,困难的部分似乎是使用datepicker来处理多个输入。如果你想在焦点上打开日期选择器,Datepicker不会轻易处理两个输入 - 肯定有一个&#39;技巧&#39;。如果将datepicker与隐藏输入(display:none)相关联,则在可见输入之前创建该隐藏输入,然后让您的可见输入在click事件上显示datepicker,一切都很好。

所以我采取了原始答案,并做了一些小改动:

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

以下是代码:

&#13;
&#13;
.dp-highlight .ui-state-default {
          background: #484;
          color: #FFF;
        }
&#13;
<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>
&#13;
import java.util.Scanner;
import java.util.Stack;

public class Stack_1 {
    public static void main(String[] args) {
        String val;
        Scanner input = new Scanner(System.in);
        System.out.println("Enter Text: ");
        val = input.nextLine();
        push(val);
    }

    public static void push(String str) {
        Stack<Character> stk = new Stack<Character>();
        for (int i = 0; i < str.length(); i++) {
            stk.push(str.charAt(i));
        }
        System.out.println(stk);
        String reverseString = "";
        String original = "";
        int length = original.length();
        for (int i = length - 1; i >= 0; i--)
            reverseString = reverseString + original.toUpperCase().charAt(i);
        if (original.toUpperCase().equals(stk))
            System.out.println("The string is a palindrome.");
        else if (reverseString.toUpperCase().equals(stk))
            System.out.println("The string is not a palindrome.");
    }
}
&#13;
&#13;
&#13;

还有很多事情需要改进。需要更好的输入验证。特别想得到日期选择器“完成”#39;按钮在内联模式下工作,但是datepicker并没有针对这种情况设计(在datepicker中有一个可设置的Done按钮标志肯定会很好)。所以现在,我在输入字段旁边有一个俗气的完成按钮,实际上什么都不做(除了鼓励用户将焦点从日期选择器上移开以关闭日期选择器)。