日历_日历算法_js生成日历的算法讲解,日历插件讲解
2017-01-01 18:32

日历插件,说来几乎所有的前端都不陌生,或许你用过My97dater,Jquery的日历插件,easyUI的日历插件。他们确实都是很好用的日历插件,但也并不是能满足我们系统所有对日历插件的需求,以及移动端也需要用到日历插件,甚至我们的日历插件要按照设计师的要求有特殊的布局要求,或者根据不同的业务需求,日历插件需要适应特殊的业务逻辑。这个时候,我们要是能自己编写日历插件多好啊,就算不能编写插件,只要我们会日历的算法,我们就可以做页面中根据业务和设计师的要求,实现符合要求的日历功能。

   今天我们就从日历插件的算法开始讲起。

    Calendar.png

上图是My97dater插件的一个截图,从截图我们可以看到,日历插件是信息是6行7列的日期信息。

我们可以看作是一个6*7的一个数组,那么如果我们能得到这么一个数组,那么用for循环,我们就可以遍历生成日历了,之后就可以对他们添加事件等等操作。

var dateJson=[
{year:2016,month:12,day:24,place:'cur'}
...
... 
];

我们定义日历数据时这么一个json格式的数据,

place的参数分为cur,pre,after,分别表示是上一个月,当月,下一个月的日期。

好了,那么我们创建一个函数用来获取dateJson数据。

//@params
//date-需要获取的月份
//startdt-有效日期的开始日期
//enddt-有效日期的结束日期
function getDateJson(date){
    .......
}

定义了获取dateJson的方法,下面就要做此方法中来计算生成json数据。

1,首先定义平年和闰年月份天数的数组,闰年的2月比平年2月多一天。

var months=[31,28,31,30,31,30,31,31,30,31,30,31];
var months2=[31,29,31,30,31,30,31,31,30,31,30,31];

2,然后我们再定义一个根据判断是否是闰年的方法,能被400和100除尽或者能被4除尽的是闰年。

function isLeap(yy){
   var mrun=yy%100==0&&yy%400==0?true:(yy%4==0?true:false);
   return mrun;
}

3,实现getDateJson方法。

function getDateJson(date){
    //获取要绘制月份的年月,
    var yy=date.getFullYear();
    var mm=date.getMonth();
    //判断是否是闰年
    var isleap=isLeap(yy);
    //获取应该使用的月份数组。
    var month=isleap?months2:months;
    //定义此月的1号的日期,获取其星期。
    var begin_date=new Date(yy,mm,1);
    var begin_week=begin_date.getDay();
    //获得上个月应该显示几天
    var pre_num=begin_week;
    //数组的总个数
    var const_num=7*6;
    //当月的天数
    var cur_num=month[mm];
    //下个月的天数
    var after_num=const_num-cur_num-pre_num;

    var preyy=yy;
    var premm=mm;
//月份-1小于0,则前一月为上一年
    if(premm==0) {
        preyy -= 1;
    }
    //上个月的月份以及天数
    premm=premm-1<0?11:(premm-1);
    var pre_max=month[premm];

    //下个月的月份
    var afteryy=yy;
    var aftermm=mm;
    if(aftermm==11){
        afteryy+=1;
    }
    aftermm=aftermm+1>11?0:(aftermm+1);
  //定义日历数组。
    var dateJson=[];
    //循环得到上个月的日期。
    for(var i=pre_num;i>0;i--){
        var obj={year:preyy,month:premm,day:(pre_max-i+1),place:'pre'};
        dateJson.push(obj);
    }
    //循环添加当月日期
    for(var i=1;i<=cur_num;i++){
        var obj={year:yy,month:mm,day:i,place:'cur'};
        dateJson.push(obj);
    }
    //循环添加下个月的日期。
    for(var i=1;i<=after_num;i++){
        var obj={year:afteryy,month:aftermm,day:i,place:'after'};
        dateJson.push(obj);
    }
    return dateJson;
}

通过上面代码,逻辑很简单,我们只需要month加一减一,就能获得上个月和下个月的月份,日历显示的总天数是6*7=42天,那么显示上个月几天,我们要根据当月的1号是星期几来决定,星期日则显示0天,星期六则显示6天,所以上个月显示的日期天数就是当月1号的星期值。下个月显示的天数更好计算,42-当月天数-上月天数。定义好dateJson数组,运用三个for循环分别把上个月,当月和下个月的日期push到数组中。其中注意上个月的遍历要你想遍历。

  得到json数据后,我们需要把json转换成dom元素或者innerHTML数据的字符串,我们就用table来渲染json数据

function drawCalendar(){
    var year=dom_yy.value;
    var mm=dom_mm.value;
    var udate=new Date(year,mm,1);
    var json=getDateJson(udate);
    var str="<table class='date_table'>"
    for(var i=0;i<json.length;i++){
    //7天一行,因为从0开始,所以+1对7求余。
    //为1是tr的开始,为0为tr的结束。
        if((i+1)%7==1){
            str+="<tr>";
        }
        var obj=json[i];
        var oclass="";
        //根据是不是当月添加不同的class。
        switch (obj.place){
            case "pre":oclass="pre_date";break;
            case "cur":oclass="cur_date";break;
            case "after":oclass="after_date";break;
        }
        str+="<td class='"+oclass+"' >"+obj.day+"</td>";
        if((i+1)%7==0){
            str+="</tr>";
        }
    }
    str+="</table>";
    return str;
}

通过循环生成字符串,就生成了一个日历table,日历的绘制就算完成了。

冬天.png

我用上面讲述的方法的写了个demo,你可以狠狠点击这里,查看我们生成的日历

虽然渲染完了了日历,我们还需要给日历添加上点击事件才算一个完整的日历。这个需要我们在生成日历字符串的时候做一些处理。

str+="<td class='"+oclass+"'  my-date='"+obj.year+"-"+obj.month+"-"+obj.day+"'>"+obj.day+"</td>";

把每一个日期的dom元素通过自定义属性绑定上对应的日期,通过addEventListener或者jquery绑定事件,获取其自定义属性,就知道点击元素的日期了。这个是我们我们通过页面中普通方法写的日历算法。为了方便使用,我们应该把日历写成js插件的形式以方便我们调用。插件写法又是一大篇幅文章了,这里就不絮说了。

 我们写日历的时候通常还需要我们的日历有一个最小日期,一个最大日期,这中间的才是有效日期,说通俗点就是有效日期可以点击处理,无效日期不能点击。这个需要我们把获取的日期和startDt,endDt进行比较,简单的比较方式,你可以用Date对象的getTime()方法获取自1970年1月1日开始计算的毫秒数,比较毫秒数的大小就可以判断是否是有效日期了,也可以通过年月日的逐个判断来判断是否是有效日期。

 今天给大家介绍的这个日历算法很容易懂,而且逻辑性也不复杂。我之前写的日历插件,所用的算法比这个要麻烦很多,而且理解起来很是费劲。本来想给大家介绍那个算法呢,突然灵光一闪,发现了这个算法更简便,就把这个算法介绍给大家了。

 原来日历算法这么简单,我们以后遇到特殊业务的特殊需求也可以不同网上搜有没有合适的日历插件了,自己动手写一个符合要求的就可以了。

原创文章,转载请注明来自:妹纸前端-www.webfront-js.com.
阅读(3037)
辛苦了,打赏喝个咖啡
微信
支付宝
妹纸前端
妹纸前端工作室 | 文章不断更新中
京ICP备16005385号-1