9

カスタムの START および END 日付セレクターを作成しようとしていますが、残念ながら設計のために jquery UI の Datepicker を使用できないため、日付を 3<select>秒で分割するという昔ながらのやり方に固執しています。

この機能を使い続けるために、少なくとも複雑な部分があります:

  • 月ごとに日を意味のあるものにします (2 月 31 日を選択可能にしたくない、..)
  • 次に START から END セレクターまでを設定します

したがって、少なくともその部分を抽象化できるように、日付の計算を JavaScript の Date() オブジェクトに委譲する方がよいと考えました。

私はほとんどそこにいます、

しかし、Date() オブジェクトが正しい日付を伝える方法はいくつかありますが、両方のセレクターは前の日の各セットを表示します (たとえば、上位 28 日間は 2 月ではなく 3 月に発生します)

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

それ以外の場合は、前の月に戻るためです。ここで最も人気のある回答のコメントで詳細を読むことができます: javascript を使用して指定された月の日数を取得しますか?

2番目:削除しました

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

すでに持っているので

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

月末に自動的に月が切り替わります。

3 番目:この部分には月の代わりに dia がありました:

/* 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);
        }

- - 追加した - -

4 つ目: 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 に答える
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 日を選択可能にしたくない、..)
  • 次に START から END セレクターまでを設定します

...

ただし、Date() オブジェクトが正しい日付を伝える方法はいくつかありますが、両方のセレクターは前の日の各セットを表示します (たとえば、上位 28 日間は 2 月ではなく 3 月に発生します)。

以下を見ると、小さなモジュラー関数を使用して、上記のすべてを処理します。

  • maxDay() - 月と年を指定すると、その年のその月の最大日数を返します
  • createAry() - 指定された最小、最大、およびオプションの値の配列を、最小から最大までの配列、または最小インデックスと最大インデックスの間の値配列の一部を返します
  • days() - 指定された最小日と月と年はmaxDay()を使用して最大日を取得します。createAry ()を使用して、日の<select>オプションを入力するためにすぐに使用できる配列を返します
  • months() - 最小の月と月のテキスト値の配列 (「jan」、「feb」など) を指定すると、 createAry()を使用して、月の<select>オプションを設定するために使用できる配列を返します
  • years() - min year を指定すると、 MAXYEAR定数とcreateAry()を使用して、年の<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 に答える
1

編集:余分なロジックを削除するためにいくつかのコードをリファクタリングしました

3 つのユーティリティ関数を使用して、開始日と終了日のドロップダウンを更新しました。

  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 に答える
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 に答える