9

我正在尝试构建一个自定义 START 和 END 日期选择器,但不幸的是,由于设计我将无法使用 jquery UI Datepicker,所以我坚持在 3<select>秒内拆分日期的旧时尚

为了保持这个特性可用,我们发现这个 - 至少 - 复杂的部分:

  • 让每个月的日子都有意义(不想选择 2 月 31 日,..)
  • 将 next thay 从 START 设置为 END 选择器

所以我认为最好将日期计算委托给javascript Date() 对象,这样至少我可以抽象出那部分。

我快到了,

但是有些 Date() 对象如何告诉正确的日期,但是两个选择器都显示了前一天的每一天(例如,前 28 天发生在 3 月而不是 2 月)

    $(function(){

months = ['jan','feb','mar','apr','may','jun','jul','ago','sep','oct','nov','dec'];
        /* Cachear selects */
        var $ld = $('select[name=llegada-dia]');
        var $lm = $('select[name=llegada-mes]');
        var $ly = $('select[name=llegada-ano]');
        var $sd = $('select[name=salida-dia]');
        var $sm = $('select[name=salida-mes]');
        var $sy = $('select[name=salida-ano]');
        var manyDays = function( month, year ){
            var fecha = new Date(year, (month) , 0);
            return fecha.getDate();
        }
        var paintCals = function( day, month , year ){
            if(day == '') day = 1;
            if(month == '') month = 0;
            if(year == '' ) year = 2013;
            //month = month -1;
            var fecha = new Date( year, month , day );          
            var dia = fecha.getDate();
            var mes = fecha.getMonth();
            var anyo = fecha.getFullYear();
            var dias_mes = manyDays( mes,anyo );
            /* Generate next date = fecha + 1 */
            var next_fecha = fecha;

            next_fecha.setDate(next_fecha.getDate() + 1); 
            next_fecha.setMonth(fecha.getMonth() + (dia == dias_mes ? 1 : 0)   ); 
            next_fecha.setFullYear(fecha.getFullYear() + (mes == 12 ? 1 : 0)  ); 

            var next_dia = next_fecha.getDate();
            var next_mes = next_fecha.getMonth();
            var next_anyo = next_fecha.getFullYear();
            var next_dias_mes = manyDays( next_mes, next_anyo ) ;
            $ld.empty();
            for(var tmpdia = 1; tmpdia <= dias_mes; tmpdia++){
                var doption = $('<option>').attr( 'value',tmpdia )
                                           .text( tmpdia );
                if(dia == tmpdia && dia != ''){
                    doption.attr('selected', 'selected');
                }
                $ld.append(doption);
            }
            /* Actualizar dias salida */
            $sd.empty();
            for(var tmpdia = next_dia; tmpdia <= next_dias_mes; tmpdia++){
                var doption = $('<option>').attr( 'value' , tmpdia )
                                           .text(tmpdia);
                if(next_dia == tmpdia && next_dia != ''){
                    doption.attr('selected', 'selected');
                }
                $sd.append(doption);
            }
            /* Actualizar meses salida */
            $sm.empty();
            for(var tmpmes = next_mes ; tmpmes < 12; tmpmes++){
                var doption = $('<option>').attr('value',tmpmes)
                                           .text(months[tmpmes]);
                if(dia == tmpdia && dia != ''){
                    doption.attr('selected', 'selected');
                }
                $sm.append(doption);
            }
            /* Actualizar anyos salida */
            $sy.empty();
            for(var tmpanyo = next_anyo; tmpanyo <= 2020; tmpanyo++){
                var doption = $('<option>').attr('value',tmpanyo)
                                           .text(tmpanyo);
                if(next_anyo == tmpanyo && next_anyo != ''){
                    doption.attr('selected', 'selected');
                }
                $sy.append(doption);
            }
        } 
        $('.arrival select').on('change',function(){
            var ldia = $ld.val();
            var lmes = $lm.val();
            var lano = $ly.val();
            var ldias = paintCals(ldia,lmes,lano);
        });
    })

在这里可以摆弄:

http://jsfiddle.net/96qyH/8/

知道我在这里缺少什么吗?

4

7 回答 7

2

首先: manyDays fn 需要是:

var days_in_month = new Date(year, month+1, 0);

因为否则它会回到上个月。您可以在此处最流行的答案的评论中阅读更多相关信息:Get number days in a specified month using javascript?

第二:我删除了

next_fecha.setMonth(fecha.getMonth() + (dia == dias_mes ? 1 : 0)   );

既然你已经有了

next_fecha.setDate(next_fecha.getDate()+1);

它在月底自动切换月份。

第三:这部分有直径而不是月份:

/* Actualizar meses salida */
        $sm.empty();
        for(var tmpmes = next_mes ; tmpmes < 12; tmpmes++){
    var doption = $('<option>').attr('value',tmpmes).text(months[tmpmes]);
            if(next_mes == tmpmes && next_mes != ''){
                console.log('fired');
      doption.attr('selected', 'selected');
            }
            $sm.append(doption);
        }

- - 添加 - -

第四:还需要检查是否存在 2 月 31 日。如果不是,则 day 应该是该月的最后一天。否则 Date 对象不知道如何处理日期并且给出了错误的日期。

只需要添加一个检查:

var check_fecha = new Date( year, month );          
        check_mes = check_fecha.getMonth();
  check_anyo = check_fecha.getFullYear();
  var check_dias_mes = manyDays( check_mes, check_anyo );

  if(day > check_dias_mes)
    day = check_dias_mes;

希望它能解决它,在这里查看:http: //jsfiddle.net/96qyH/13/

于 2013-10-17T19:27:39.037 回答
2

如果需要源代码

我已经为你找到了一些答案!这可能会帮助你!:) 我也创建了一个插件,但你不需要它是唯一的答案。所以这里有什么可以帮助你。如果你想看一下代码,你可以在这里获取源代码:https ://github.com/the-vs-organisation/vdatetimepicker

第一个的解决方法

让每个月的日子都有意义(不想选择 2 月 31 日,..)

对于这个问题,我使用月份列表中的值作为:

var month = $('#monthval').attr('id');
if(month == "February") {
  // hide the last few list items..
}

然后以此类推。您可以在我的插件中查看源代码。您还将了解如何与其他月份进行互动。

您可以使用id容器作为其值,因为我们不会使用select因为您无法设置style属性的样式。因此,您将需要一个自定义创建的日期时间选择器。

禁用列表中的任何项目对于 UI 来说都不是一个好主意,因此您可能需要隐藏它。隐藏它不会打扰 UI 或用户自己。由于该项目将不可用,他不必担心这件事。

第二个

我不确定你想要什么,所以我会留下它而不是给出一个模糊的答案。

我的假设

如果你想获得剩余时间或者如果你想比较它们,那么你可以使用这个:

var time = "some_string_of_time";
var curTime = new Date();
// now time to get the seconds between it..
var seconds = Math.floor((curTime - Time) / (1000));
// now write them..
if (seconds > 0 && seconds < 60) {// seconds..
    $('element') = seconds + " seconds ago";
}

隐藏值

但是有些 Date() 对象如何告诉正确的日期,但是两个选择器都显示了前一天的每一天(例如,前 28 天发生在 3 月而不是 2 月)

这可以在我的代码中select以及在我的代码中最小化。您需要使用的只是一个简单的类或 id 以及月份选择器的点击事件。隐藏过多的列表项(如果有)。否则显示。在我的插件中,一月和十二月总是有 31 天,二月有 28 天。这完全取决于在月份下拉列表中选择的列表项。您可以使用 jQuery 更新其他 div 中的代码。

如果你不关心 UI

如果您不想设置 UI 样式,您是否尝试过使用输入工具?

<input type="date" name="datetime" />

这是一个浏览器生成的。当没有其他东西派上用场时,您始终可以使用它。

如何从我的插件访问数据。

.vdtpckr一旦您使用他们的 ID 填写了字段,您总是可以尝试从中获取数据,例如:

var month = $('.vmonthval').attr('id');

这样,您可以从中获取值。

如果您还需要什么,请在下方评论!:) 也尝试从 github 查看源代码。你会从代码中得到很多想法。

于 2013-10-23T05:07:38.043 回答
1

当 Date 被调用为具有多个参数的构造函数时,如果值大于它们的逻辑范围(例如,提供 13 作为月份值或 70 作为分钟值),则将调整相邻值。例如 new Date(2013,13,1) 等价于 new Date(2014,1,1),两者都为 2014-02-01 创建一个日期。其他值也类似:new Date(2013,2,1,0,70) 等价于 new Date(2013,2,1,1,10),它们都为 2013-03-01T01:10:00 创建日期。

这是来自MDN的日期构造函数的注释

问题在于以下功能

var manyDays = function( month, year ){
  var fecha = new Date(year, (month) , 0);
  return fecha.getDate();
}

当您使用 0 作为获得上个月的日期时

例如

var date1 = new Date(2013,2,0)
console.log(date1.getMonth()); // will print 1 = Feb

var date2 = new Date(2013,2,1)
console.log(date2.getMonth()); // will print 2 = March

var date3 = new Date(2013,2,32)
console.log(date3.getMonth()); // will print 3 = April

我不知道在Javascript中获取一个月天数的任何正确方法。一个知道的技巧是像这样修改你的manyDays方法。

var manyDays = function( month, year ){
  // Note: month + 1
  var fecha = new Date(year, month+1 , 0);
  return fecha.getDate();
}

您不需要执行以下操作

next_fecha.setDate(next_fecha.getDate() + 1); 
next_fecha.setMonth(fecha.getMonth() + (dia == dias_mes ? 1 : 0)   ); 
next_fecha.setFullYear(fecha.getFullYear() + (mes == 12 ? 1 : 0)  );

它可以替换为

next_fecha.setDate(next_fecha.getDate() + 1);

因为向日期对象添加一天将适当地更新日期、月份、年份等。

在评论中回答问题

此版本中处理月份的 for 循环有错误。您使用了错误的变量。分别更改diatmpdianext_mestmpmes

应该是这样的

$sm.empty();
for(var tmpmes = next_mes ; tmpmes < 12; tmpmes++){
  var doption = $('<option>').attr('value',tmpmes).text(months[tmpmes]);
  if(next_mes == tmpmes && next_mes != ''){
    doption.attr('selected', 'selected');
  }
  $sm.append(doption);
}

以下是修复了上述问题的更新版本。

http://jsfiddle.net/96qyH/14/

于 2013-10-21T05:01:24.037 回答
1

编辑:重构一些代码以删除额外的逻辑

我使用了三个实用函数来更新开始和结束日期下拉列表。

  1. daysInMonth- 获取一年中指定月份的天数
  2. adjustDates- 根据所选月份更新下拉列表中的天数。注意:这只是附加/删除选项,而不是从头开始重建。
  3. resetDates- 重置开始月份和年份

我重写了您的代码并尝试实现您在演示代码中的相同逻辑。查看我的演示,让我知道它是否适合您。

演示:http: //jsfiddle.net/ByWhz/1/

完整代码:

$(function () {
    months = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dec'];

    /* Cachear selects */
    var $ld = $('select[name=llegada-dia]');
    var $lm = $('select[name=llegada-mes]');
    var $ly = $('select[name=llegada-ano]');
    var $sd = $('select[name=salida-dia]');
    var $sm = $('select[name=salida-mes]');
    var $sy = $('select[name=salida-ano]');

    //http://stackoverflow.com/a/1184359/297641
    function daysInMonth(month, year) {
        return new Date(year, month, 0).getDate();
    }

    function adjustDates(selMonthDates, $sel) {
        var $options = $sel.find('option');
        var dates = $options.length;
        //append/remove missing dates
        if (dates > selMonthDates) { //remove
            $options.slice(selMonthDates).remove();
        } else { //append
            var dateOptions = [];
            for (var date = dates + 1; date <= selMonthDates; date++) {
                dateOptions.push('<option value="' + date + '">' + date + '</option>');
            }
            $sel.append(dateOptions.join('')); //reduces DOM call
        }
    }

    function resetDates() {
        $lm.val(function (i, v) {
            return (v == '') ? '0' : v;
        });
        $ly.val(function (i, v) {
            return (v == '') ? '2013' : v;
        });
    }

    var paintCals = function (day, month, year) {

        resetDates();

        //adjust start date
        var selMonthDates = daysInMonth((parseInt($lm.val(), 10) + 1), $ly.val());
        adjustDates(selMonthDates, $ld);

        //If current day selection > number of days in selected month then set the day to max allowed day
        if (day > selMonthDates) {
            day = selMonthDates;
            $ld.val(day); //update selection
        }

        //selected start date
        var selectedDate = new Date(year, month, day);

        //next day from start date
        var nextDay = new Date(selectedDate.getTime() + 86400000);

        //lets build the end year drop down
        var tmpArr = [];
        for (var yrs = parseInt(nextDay.getFullYear(), 10); yrs <= 2020; yrs++) {
            tmpArr.push('<option value="' + yrs + '">' + yrs + '</option>');
        }
        $sy.empty().append(tmpArr.join('')); //set the YEARS
        //simply set the month
        $sm.val(nextDay.getMonth()); //set the month

        //adjust end date
        selMonthDates = daysInMonth(parseInt(nextDay.getMonth(), 10) + 1, nextDay.getFullYear());
        adjustDates(selMonthDates, $sd);

        $sd.val(nextDay.getDate()); //set the date

        $('#log').empty().append('Fecha: ' + selectedDate).append('<br>');
        $('#log').append('Siguiente: ' + nextDay);
    }

    $('.arrival select').on('change', function () {
        var ldia = $ld.val();
        var lmes = $lm.val();
        var lano = $ly.val();
        //console.log('lD/lM/lY:'+ldia,lmes,lano);

        var ldias = paintCals(ldia, lmes, lano);
    });
});
于 2013-10-22T02:10:08.187 回答
1

看看我的这个小提琴,希望这对你有用

对于 HTML

    <form name="myForm" id="myForm">
    <fieldset id='dbOne'>
        <legend>Start Date</legend>
        <label for="yearOne">Year</label>
        <select name="yearOne" id="yearOne" title="Year" class='year'></select>
        <label for="monthOne">Month</label>
        <select name="monthOne" id="monthOne" title="Month"  class='month'></select>

        <label for="dayOne">Day</label>
        <select name="dayOne" id="dayOne" title="Day"  class='day'></select>
    </fieldset>
    <fieldset id='dbTwo'>
        <legend>End Date</legend>
        <label for="yearTwo">Year</label>
        <select name="yearTwo" id="yearTwo" title="Year" class='year'></select>
        <label for="monthTwo">Month</label>
        <select name="monthTwo" id="monthTwo" title="Month"  class='month'></select>
        <label for="dayTwo">Day</label>
        <select name="dayTwo" id="dayTwo" title="Day"  class='day'></select>
    </fieldset>
</form>

和 JS

  $(function () {
        // get days in month
        function daysInMonth(month, year) {

            month = parseInt(month,10)+1;
            month=month.toString();
            return new Date(year, month, 0).getDate();
        }
        //creates an array of number, a = array size, b starting num
        var numberArray = function (a, b) {
            c = [];
            for (var i = 0; i < a; i++) {
                c[i] = i + b;
            }
            return c;
        };
        //generates numeric drop down
        function createOptions(parent, options) {
            var l = options.length;
            for (var i = 0; i < l; i++) {
                var val = options[i];
                var text = options[i];
                var node = document.createElement("option");
                node.textContent = text;
                node.value = val;
                if(i===0) node.selected='selected';
                parent.appendChild(node);

            }
        }
        //generates drop down with numeric value string text
        function getOptionFromMap(parent, map) {
            for (var i = 0; i < map.length; i++) {
                var x = map[i];
                var val = x.key;
                var text = x.val;
                var node = document.createElement("option");
                node.textContent = text;
                node.value = val;
                if(i===0) node.selected='selected';
                parent.appendChild(node);
            }

        }
        var years = numberArray(20, 2000);
        var days = numberArray(31, 1);
        var months = [{
            key: 00,
            val: "jan"
        }, {
            key: 01,
            val: "feb"
        }, {
            key: 02,
            val: "mar"
        }, {
            key: 03,
            val: "apr"
        }, {
            key: 04,
            val: "may"
        }, {
            key: 05,
            val: "jun"
        }, {
            key: 06,
            val: "jul"
        }, {
            key: 07,
            val: "aug"
        }, {
            key: 08,
            val: "sep"
        }, {
            key: 09,
            val: "oct"
        }, {
            key: 10,
            val: "nov"
        }, {
            key: 11,
            val: "dec"
        }];
        createOptions(document.getElementById('dayOne'), days);
        createOptions(document.getElementById('dayTwo'), days);
        createOptions(document.getElementById('yearOne'), years);
        createOptions(document.getElementById('yearTwo'), years);
        getOptionFromMap(document.getElementById('monthOne'), months);
        getOptionFromMap(document.getElementById('monthTwo'), months);

        $(".year,.month").bind({
            change:function(){
                var dInMonth = daysInMonth($('.month',$(this).parent()).val(), $('.year',$(this).parent()).val());
                $('.day',$(this).parent()).children().each(function(){

                    var cEle = $(this);
                    var cValue = parseInt(cEle.html(),10);
                    if(!cEle.is(':disabled') && (cValue>dInMonth)) {
                        cEle.attr({disabled:true});
                    } else if(cEle.is(':disabled') && (cValue<=dInMonth)) {
                        cEle.attr({disabled:false});
                    }
                });
            }
        });

        $('select',$('#dbOne,#dbTwo')).bind({
            change:function(){
                var dBoxOne = $('#dbOne');
                var dBoxtwo = $('#dbTwo');
                var dtOne = getDateString(dBoxOne);
                var dOne = new Date(dtOne.y,dtOne.m,dtOne.d);
                var dtTwo = getDateString(dBoxtwo);
                var dTwo = new Date(dtTwo.y,dtTwo.m,dtTwo.d);
                if(dOne>dTwo) {
                    var nextDay = parseInt(dtOne.d,10)+1;
                    //alert('a');
                    dTwo = new Date(dtOne.y,dtOne.m,nextDay.toString());
                    setDate(dBoxtwo,dTwo);
                } else {

                }
            }
        });

        function getDateString(dateBox){
            var year = $('.year',dateBox).val();
            var month = $('.month',dateBox).val();
            var day = $('.day',dateBox).val();
            var da = year+"/"+month+"/"+day;
            var d = {y:year,m:month,d:day};
            return d;

        }

        function setDate(dateBox,dateObj){
            var year = dateObj.getFullYear();
            var month = dateObj.getMonth();
            var day = dateObj.getDate();

            $('.year',dateBox).val(year);
            $('.month',dateBox).val(month);
            $('.day',dateBox).val(day);

        }



    });
于 2013-10-22T23:55:08.807 回答
1

这是我的努力 - 涵盖所有边缘案例

到目前为止,它是一个经过充分测试的强大日期选择器,并回答了以下问题:

  • 让每个月的日子都有意义(不想选择 2 月 31 日,..)
  • 将 next thay 从 START 设置为 END 选择器

...

但是有些 Date() 对象如何告诉正确的日期,但是两个选择器都显示了前一天的每一天(例如,前 28 天发生在 3 月而不是 2 月)

如果您看下面,我会使用小型模块化功能来处理上述所有内容以及更多内容:

  • maxDay() - 给定月份和年份,它返回该年该月的最大天数
  • createAry() - 给定最小值、最大值和可选值数组,返回从最小值到最大值的数组或最小值和最大值索引之间的值数组的一部分
  • days() - 给定最小的日期和月份和年份,使用maxDay()来获取最大天数。使用createAry()返回一个数组,准备用于填充日期<select>选项
  • months() - 给定最小月份和月份文本值数组(如“jan”、“feb”等)使用createAry()返回准备用于填充月份<select>选项的数组
  • years() - 给定 min year 使用MAXYEAR常量和createAry()来返回一个准备好用于填充 year <select>选项的数组
  • updateSelectOptions() - 给定一个 jQuery DOM <select>元素,一个来自day()month()year()的选项文本数组和选定的选项索引,清空然后填充<select>;使用数组值并选择适当的选项。
  • updateTos() - 如有必要,更新结束日期滚动超过开始日期,并根据开始日期值进行最小月、日和年计算。调用updateSelectOptions()为月、日和年提供 jQuery <select> DOM 元素和由month()day()year()返回的数组,以使用适当的文本值更新<select>选项并选择正确的当前选项。
  • update() - 使用选定<select>选项中的月、日和年在内部使用new Date()更新开始日期或结束日期。对于Start Date ,使用days()maxDay()调用updateSelectOptions( )以根据月份和年份限制天数并选择当前选项。调用updateTos()以更新结束日期及其<select>选项。

jsFiddle:

小提琴

HTML:

<form>
    <fieldset class="dateField">
        <legend>Start Date</legend>
        <label for="fromMonth">Month</label>
        <select id="fromMonth" class='monthSelect'></select>
        <label for="fromDay">Day</label>
        <select id="fromDay" class='daySelect'></select>
        <label for="fromYear">Year</label>
        <select id="fromYear" class='yearSelect'></select>
    </fieldset>
    <fieldset class="dateField">
        <legend>End Date</legend>
        <label for="toMonth">Month</label>
        <select id="toMonth" class='monthSelect'></select>
        <label for="toDay">Day</label>
        <select id="toDay" class='daySelect'></select>
        <label for="toYear">Year</label>
        <select id="toYear" class='yearSelect'></select>
    </fieldset>
</form>
<input type="button" id="reset" class="resetButton" value="Reset" />

JavaScript:

'use strict';

var fromDay = $('#fromDay'),
    fromMonth = $('#fromMonth'),
    fromYear = $('#fromYear'),
    toDay = $('#toDay'),
    toMonth = $('#toMonth'),
    toYear = $('#toYear'),
    reset = $('#reset'),
    CURDATE = new Date(),
    curFromDate,
    curToDate,
    MINYEAR = 2000,
    NUMYEARS = 40,
    MAXYEAR = MINYEAR + NUMYEARS - 1,
    MAXDATE = new Date(MAXYEAR, 11, 31),
    MONTHS = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'];

function maxDay(params) { // {month, year}

    params.month = params.month || 0;
    params.year = params.year || MINYEAR;

    return new Date(params.year, (params.month - 0) + 1, 0).getDate();
}

function createAry(params) { // { min, max, values }

    var i,
        ary = [];

    params.values = params.values || [];

    if (params.values.length !== 0) {
        return params.values.slice(params.min, params.max + 1);
    }

    for (i = 0; i < params.max - params.min + 1; i++) {
        ary[i] = params.min + i;
    }

    return ary;
}

function days(params) { // {minDay, month, year}

    var max;

    params.month = params.month || 0;
    params.year = params.year || MINYEAR;

    max = maxDay({
        month: params.month,
        year: params.year
    });

    params.minDay = params.minDay || 1;

    return createAry({
        min: params.minDay,
        max: max
    });
}

function months(params) { // {minMonth, months}

    params.minMonth = params.minMonth || 0;

    return createAry({
        min: params.minMonth,
        max: 11,
        values: MONTHS
    })
}

function years(params) { // {minYear}

    params.minYear = params.minYear || MINYEAR;

    return createAry({
        min: params.minYear,
        max: MAXYEAR
    });
}

function updateSelectOptions(params) { // {select, options, current]

    params.select.empty();

    params.options.forEach(function (e, i) {
        params.select.append($('<option></option>').prop("selected", i === params.current).text(e));
    });

}

function updateTos() {

    var minDay = 1,
        minMonth = 0,
        minYear = curFromDate.getFullYear();

    if (curToDate <= curFromDate) {
        curToDate = new Date(curFromDate.getFullYear(), curFromDate.getMonth(), curFromDate.getDate() + 1);

        minYear = curToDate.getFullYear();

        if (minYear === curFromDate.getFullYear()) {
            minMonth = curToDate.getMonth();
        }
        if (curFromDate.getMonth() === curToDate.getMonth()) {
            minDay = curToDate.getDate();
        }
    } else if (curFromDate.getFullYear() === curToDate.getFullYear()) {
        minMonth = curFromDate.getMonth();
        if (curFromDate.getMonth() === curToDate.getMonth()) {
            minDay = curFromDate.getDate() + 1;
        }
    } else if (curFromDate.getDate() === 31 && curFromDate.getMonth() === 11) {
        minYear++;
    }

    updateSelectOptions({
        select: toDay,
        options: days({
            minDay: minDay,
            month: curToDate.getMonth(),
            year: curToDate.getFullYear()
        }),
        current: curToDate.getDate() - minDay
    });
    updateSelectOptions({
        select: toMonth,
        options: months({
            minMonth: minMonth,
            months: MONTHS
        }),
        current: curToDate.getMonth() - minMonth
    });
    updateSelectOptions({
        select: toYear,
        options: years({
            minYear: minYear
        }),
        current: curToDate.getFullYear() - minYear
    });
}

function update(params) { // {toOrFrom}

    var day,
        month,
        year,
        max,
        date;

    if (params.toOrFrom === 'from') {
        day = fromDay.find("option:selected").text();
        month = MONTHS.indexOf(fromMonth.find("option:selected").text());
        year = fromYear.find("option:selected").text();
    } else {
        day = toDay.find("option:selected").text();
        month = MONTHS.indexOf(toMonth.find("option:selected").text());
        year = toYear.find("option:selected").text();
    }
    max = maxDay({
        month: month,
        year: year
    });

    if (day > max) {
        day = max;
    }
    date = new Date(year, month, day);

    if (params.toOrFrom === 'from') {
        if (date >= MAXDATE) {
            alert('The date you entered is later than the latest allowed date.  Please enter a different date.');

            fromDay.prop("selectedIndex", curFromDate.getDate() - 1);
            fromMonth.prop("selectedIndex", curFromDate.getMonth());
            fromYear.prop("selectedIndex", curFromDate.getFullYear() - MINYEAR);

            return;
        }
        curFromDate = date;

        updateSelectOptions({
            select: fromDay,
            options: days({
                minDay: 1,
                month: month,
                year: year
            }),
            current: day - 1
        });

    } else {
        curToDate = date;
    }
    updateTos();
}

function onFromChange() {
    update({
        toOrFrom: 'from'
    });
}

function onToChange() {
    update({
        toOrFrom: 'to'
    });
}

function init() {
    curFromDate = new Date(CURDATE.getFullYear(), CURDATE.getMonth(), CURDATE.getDate());
    curToDate = new Date(CURDATE.getFullYear(), CURDATE.getMonth(), CURDATE.getDate());

    updateSelectOptions({
        select: fromDay,
        options: days({
            minDay: 1,
            month: curFromDate.getMonth(),
            year: curFromDate.getFullYear()
        }),
        current: curFromDate.getDate() - 1
    });
    updateSelectOptions({
        select: fromMonth,
        options: months({
            months: MONTHS
        }),
        current: curFromDate.getMonth()
    });
    updateSelectOptions({
        select: fromYear,
        options: years({
            minYear: MINYEAR
        }),
        current: curFromDate.getFullYear() - MINYEAR
    });

    updateTos();
}

fromDay.change(onFromChange);
fromMonth.change(onFromChange);
fromYear.change(onFromChange);
toDay.change(onToChange);
toMonth.change(onToChange);
toYear.change(onToChange);
reset.click(init);

init();

CSS:

fieldset.dateField {
    width: 375px;
}

select.daySelect {
    width: 45px;
    margin: 5px 10px 0 0;
}

select.monthSelect {
    width: 55px;
    margin: 5px 10px 0 10px;
}

select.yearSelect {
    width: 65px;
    margin: 5px 10px 0 0;
}

input.resetButton {
    margin: 10px 20px 0 0
}
于 2013-10-24T11:13:14.027 回答
0

请看一下这个演示:http: //jsfiddle.net/wared/XvEzz/。很抱歉完全重写了您的代码,但这对我来说是一种更容易解决问题的方法。下面的代码应该可以帮助您解决问题。它位于第 24 行,在用户选择月份时执行。为了解释这个过程,我在这里添加了一些评论。基本思想是将日期临时设置为 1,然后尽可能恢复最后选择的日期:

// saves last selected day 
day = date.getDate();
// sets day to 1 in order to prevent the month from changing
date.setDate(1);
// sets selected month
date.setMonth(this.selectedIndex);
// retrieves number of days for this month
days = getDays(date);
// restores last selected day if included in this month
if (day <= days) date.setDate(day);
// refreshes days options
feedCombo(0, getRange(1, days));
// refreshes selected day
$select.eq(idx - 1).val(date.getDate());
于 2013-10-27T09:12:20.250 回答