Index.html

<html>
<head>
    <meta charset="utf-8">
    <title>QQ空间时光轴效果</title>
    <link href="style.css" rel="stylesheet" type="text/css"/>
</head>
<body>

<!-- 模版定义 -->
<div class="hide">
    <div id="tpl_scrubber_year">
        <a href="javascript:;" onclick="showYear({year},this)" class="s_year" id="scrubber_year_{year}">{year}
            {list}
        </a>
    </div>

    <div id="tpl_scrubber_month" >
        <a href="javascript:;" class="s_month {year}_month" onclick="showMonth({year},{month},this)" id="scrubber_month_{year}{month}" >{month}月</a>
    </div>

    <div id="tpl_content_year">

        <div class="c_year" id="content_year_{year}">{year}</div>
        {list}

    </div>

    <div id="tpl_content_month">

        <div class="c_item c_item_{leftOrRight} content_date_{year}{month} {isFirst}">

            <div class="c_i_icon_arrow"></div>
            <div class="c_i_icon_dot"><div class="c_i_icon_dot_child"></div></div>

            <div class="c_i_head">

                <div class="c_i_head_title">
                    <div class="c_i_head_title_icon">{lunar}</div>
                    {date}
                </div>
                <div class="c_i_head_intro">
                    <i class="ui_ico quote_before"></i>
                    {intro}
                    <i class="ui_ico quote_after"></i>
                </div>
            </div>
            <div class="c_i_media">
                {media}
            </div>
            <div class="c_i_footer">
                <div class="c_i_footer_info">
                    <a href="javascript:void(0)" class="op_zan" title="赞">
                        <i class="ui_ico ico_zan"></i>({like})</a>
                    <a href="javascript:void(0)" class="op_pin" title="评论">
                        <i class="ui_ico ico_com">评论</i>({comment})</a>
                </div>
                <div class="c_i_footer_like">
                    {like_format}人觉得很赞
                </div>
            </div>

        </div>

    </div>

</div>
<!--  网页内容 -->

<div class="top"></div>
<div class="header"></div>

<div class="container">



    <div class="scrubber" id="scrubber"> <!-- 时序列表 -->
        <!--
                    <a href="javascript:;" onclick="scroll(0)">现在</a>

                    <a href="javascript:;" onclick="showYear(2014,this)" class="s_year">2014
                        <a href="#" class="s_month 2014_month">3月</a>
                    </a>

                    <a href="javascript:;" onclick="showYear(2015,this)" class="s_year">2015
                        <a href="#" class="s_month 2015_month">3月</a>
                    </a>
        -->
    </div>


    <div class="content" id="content"> <!-- 内容 -->



    </div>
</div>

<script type="text/javascript" src="data.js"></script>
<script type="text/javascript" src="fx.js"></script>
<script type="text/javascript" src="GetLunarDay.js"></script>
<script type="text/javascript" src="app.js"></script>

</body>
</html>

style.css

* {
    margin: 0;
    padding: 0;
}

body {
    background: #fff;
    margin: 0px;
    padding: 0;
    padding-top: 41px;
    background: url(images/1.jpg) #1c0c0f center 0 no-repeat fixed;
}

.top {
    width: 100%;
    top: 0px;
    height: 41px;
    background-color: #001E3B;
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
    position: fixed;
    z-index: 999;
}

.header {
    height: 200px;
    background-color: rgba(255, 255, 255, .2);
    width: 960px;
    margin: 0px auto;
}

.container {
    width: 960px;
    min-width: 960px;
    margin: 0px auto;
    position: relative;
}

.hide {
    display: none;
}

.clear {
    clear: both;
    height: 40px
}

.scrubber {
    position: absolute;
    top: 29px;
    left: 0px;
    width: 47px;
    z-index: 999
}

.scrubber a {
    height: 26px;
    line-height: 26px;
    padding-right: 5px;
    font-size: 12px;
    color: #a5a5a5;
    text-decoration: none;
    display: block;
    border-right: 2px solid #c8c8c8;
    border-right-color: rgba(200, 200, 200, .5);
    text-shadow: 0 1px 1px rgba(0, 0, 0, .3);
    text-align: right;
}

.scrubber a:hover,
.scrubber a.cur {
    border-right-color: #7ebad0;
    color: #7ebad0;
    font-weight: bold;
}

.scrubber a:hover {
    text-decoration: underline;
}

.scrubber a.cur:hover {
    text-decoration: none;
}

.spine {
    display: block;
    width: 3px;
    height: 100%;
    background: #eee;
}

#scrubber .s_month {
    display: none;
}

.content {
    min-height: 1000px;
    padding-left: 160px;
    padding-top: 50px;
    background: url(images/spine.png) repeat-y 121px 0;
    position: relative;
}

.c_year {
    height: 30px;
    line-height: 30px;
    color: #a5a5a5;
    text-shadow: 0 1px 1px rgba(0, 0, 0, .3);
    font-weight: bold;
    font-size: 14px;
    position: relative;
    left: -90px;
    clear: both;
}

.c_item {
    width: 370px;
    background: #fff;
    height: auto;
    margin: 20px 30px 0 0;
    position: relative;
    border-radius: 4px;
    color: #888;
}

.c_item_left {
    float: left;
}

.c_item_first {
    margin-top: -20px;
}

.c_item_right {
    float: right;
}

.c_item_right .c_i_icon_dot {
    left: -443px;
}

.c_i_icon_arrow {
    position: absolute;
    height: 0px;
    border-color: transparent #e2e2e2 transparent transparent;
    border-width: 10px 10px 10px 0;
    border-style: dashed solid dashed dashed;
    border-right-color: #fff;
    left: -10px;
    top: 20px;
}

.c_i_icon_dot {
    width: 11px;
    height: 11px;
    border-radius: 11px;
    position: absolute;
    left: -43px;
    top: 25px;
    background: #fff;
}

.c_i_icon_dot_child {
    width: 7px;
    height: 7px;
    border-radius: 7px;
    position: absolute;
    left: 2px;
    top: 2px;
    background: #b3dae9;
}

.c_i_head {
    padding: 15px 15px 0px 15px;
}

.c_i_head_title {
    height: 46px;
    line-height: 46px;
    font-size: 28px;
    padding: 0px 0px 10px 56px;
    position: relative;
}

.c_i_head_intro {
    margin-bottom: 10px;
    font-size: 14px;
    line-height: 22px;
    padding: 0 15px;
}

.c_i_head_title_icon {
    width: 46px;
    height: 46px;
    background-color: #b3dae9;
    border-radius: 8px;
    position: absolute;
    left: 0px;
    top: 0px;
    overflow: hidden;
    color: #fff;
    font-size: 27px;
    line-height: 23px;
}

.c_i_media {
    padding-bottom: 10px;
    height: 277px;
    overflow: hidden;
}

.c_i_footer {
    padding: 10px 15px;
    margin: 0px 15px;
    border-top: 1px solid #d6d6d6;
    font-size: 12px;
    color: #b2b2b2;
}

.c_i_footer_info {
}

.c_i_footer_info .ui_ico {
    width: 20px;
    height: 20px;
    vertical-align: middle;
    visibility: visible;
}

.c_i_footer_like {
    line-height: 20px;
    padding-top: 5px;
}

.c_i_footer a {
    color: #b2b2b2;
    text-decoration: none;
    padding-right: 10px;
    display: inline-block;
    height: 20px;
}

.c_i_footer a:hover {
    color: #6EB8D3;
    text-decoration: underline;
}

.ui_ico, .ui_icon {
    width: 15px;
    height: 15px;
    display: inline-block;
    background-repeat: no-repeat;
    font-size: 0;
    overflow: hidden;
}

.quote_after {
    vertical-align: bottom;
    background-image: url(images/timeline.png);
    background-position: -986px -102px;
    margin-left: 5px;
}

.quote_before {
    vertical-align: top;
    background-image: url(images/timeline.png);
    background-position: -986px -85px;
    margin-right: 5px;
}

.ico_zan {
    background-image: url(images/timeline.png);
    background-position: -883px -21px;
}

.ico_com {
    background-image: url(images/timeline.png);
    background-position: -897px -42px;
}

data.js

var data = [];
data.push({
    'date'  : '2016-12-1',
    'intro' : '我要这天,再遮不住我眼,要这地,再埋不了我心,要这众生,都明白我意,要那诸佛,都烟消云散! ',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 35038,
    'comment' : 817
})

data.push({
    'date'  : '2016-11-30',
    'intro' : '金钱可以使人卑微,也可以使人卑贱,可以使人高傲,却无法使人高贵。',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 35038,
    'comment' : 817
})


data.push({
    'date'  : '2016-7-31',
    'intro' : '在这春林初盛,草长莺飞的日子,QQ空间愿你关掉电脑,放下手机,与三五好友相约青山绿水中,感受春天带来的勃勃生机···',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 302,
    'comment' : 883
})

data.push({
    'date'  : '2016-3-31',
    'intro' : '在这个世界上,一部分人选择看到丑恶与混乱, 但我选择看到美好的一面。···',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 302,
    'comment' : 883
})



data.push({
    'date'  : '2016-3-30',
    'intro' : 'You can\'t just sit there and wait for life to come to you. You have to go get it. - 你不能无所事事的坐等人生带给你一切,你必须得自己努力争取。',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 35038,
    'comment' : 817
})

data.push({
    'date'  : '2015-3-30',
    'intro' : '原来一生一世那么短暂,原来当你发现所爱的,就应该不顾一切的去追求。因为生命随时都会终止,命运是大海,当你能够畅游时,你就要尽情游向你的所爱,因为你不知道狂流什么时候会到来,卷走一切希望与梦想。',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 25038,
    'comment' : 417
})

data.push({
    'date'  : '2015-3-28',
    'intro' : '3月27日晚12点,QQ音乐年度盛典完美谢幕。这是一场由大数据决定的“巅峰对决”,5500万人次投票,265万人次观看在线直播——每一个数据都由你组成。#乐动你我,无处不乐#',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 25038,
    'comment' : 417
})

data.push({
    'date'  : '2014-2-28',
    'intro' : '3月27日晚12点,QQ音乐年度盛典完美谢幕。这是一场由大数据决定的“巅峰对决”,5500万人次投票,265万人次观看在线直播——每一个数据都由你组成。#乐动你我,无处不乐#',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 25038,
    'comment' : 417
})

data.push({
    'date'  : '2014-2-27',
    'intro' : '3月27日晚12点,QQ音乐年度盛典完美谢幕。这是一场由大数据决定的“巅峰对决”,5500万人次投票,265万人次观看在线直播——每一个数据都由你组成。#乐动你我,无处不乐#',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 25038,
    'comment' : 417
})

data.push({
    'date'  : '2014-2-26',
    'intro' : '3月27日晚12点,QQ音乐年度盛典完美谢幕。这是一场由大数据决定的“巅峰对决”,5500万人次投票,265万人次观看在线直播——每一个数据都由你组成。#乐动你我,无处不乐#',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 25038,
    'comment' : 417
})

data.push({
    'date'  : '2014-2-02',
    'intro' : '3月27日晚12点,QQ音乐年度盛典完美谢幕。这是一场由大数据决定的“巅峰对决”,5500万人次投票,265万人次观看在线直播——每一个数据都由你组成。#乐动你我,无处不乐#',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 238,
    'comment' : 417
})
data.push({
    'date'  : '2014-2-01',
    'intro' : '3月27日晚12点,QQ音乐年度盛典完美谢幕。这是一场由大数据决定的“巅峰对决”,5500万人次投票,265万人次观看在线直播——每一个数据都由你组成。#乐动你我,无处不乐#',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 25038,
    'comment' : 417
})




data.push({
    'date'  : '2013-3-31',
    'intro' : '在这春林初盛,草长莺飞的日子,QQ空间愿你关掉电脑,放下手机,与三五好友相约青山绿水中,感受春天带来的勃勃生机···',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 32102,
    'comment' : 883
})


data.push({
    'date'  : '2013-3-30',
    'intro' : '腾讯视频年度大戏,陈冠希复出之作——《探灵档案》灵异上映。一起看陈老师怎么在QQ空间里抽丝剥茧,最终破案的吧>><a href="#">http://url.cn/MbxmrY</a>',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 35038,
    'comment' : 817
})

data.push({
    'date'  : '2013-3-30',
    'intro' : '咱们Qzone有福利!即日起,在QQ空间预约《逆战》最新资料片,就能100%获得丰厚游戏大礼包——还有iPad mini、雷蛇键鼠套装等实物大奖等你来拿!还等什么?马上预约吧',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 25038,
    'comment' : 417
})

data.push({
    'date'  : '2013-3-28',
    'intro' : '3月27日晚12点,QQ音乐年度盛典完美谢幕。这是一场由大数据决定的“巅峰对决”,5500万人次投票,265万人次观看在线直播——每一个数据都由你组成。#乐动你我,无处不乐#',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 25038,
    'comment' : 417
})

data.push({
    'date'  : '2013-2-28',
    'intro' : '3月27日晚12点,QQ音乐年度盛典完美谢幕。这是一场由大数据决定的“巅峰对决”,5500万人次投票,265万人次观看在线直播——每一个数据都由你组成。#乐动你我,无处不乐#',
    'media' : '<img src="http://b248.photo.store.qq.com/psb?/eabfd933-2c89-47cc-8138-5b5463dab9e9/6prIkorOKpH.kDZWn*IhPw3v9NTSHwx3ZdRehBPs6X4!/b/dH6R3JOrDwAA&bo=gAJeA50ENwYBAFA!" width="370">',
    'like' : 25038,
    'comment' : 417
})

data.push({
    'date'  : '2013-2-27',
    'intro' : '3月27日晚12点,QQ音乐年度盛典完美谢幕。这是一场由大数据决定的“巅峰对决”,5500万人次投票,265万人次观看在线直播——每一个数据都由你组成。#乐动你我,无处不乐#',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 25038,
    'comment' : 417
})

data.push({
    'date'  : '2013-2-26',
    'intro' : '3月27日晚12点,QQ音乐年度盛典完美谢幕。这是一场由大数据决定的“巅峰对决”,5500万人次投票,265万人次观看在线直播——每一个数据都由你组成。#乐动你我,无处不乐#',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 25038,
    'comment' : 417
})

data.push({
    'date'  : '2013-2-02',
    'intro' : '3月27日晚12点,QQ音乐年度盛典完美谢幕。这是一场由大数据决定的“巅峰对决”,5500万人次投票,265万人次观看在线直播——每一个数据都由你组成。#乐动你我,无处不乐#',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 25038,
    'comment' : 417
})
data.push({
    'date'  : '2013-2-01',
    'intro' : '3月27日晚12点,QQ音乐年度盛典完美谢幕。这是一场由大数据决定的“巅峰对决”,5500万人次投票,265万人次观看在线直播——每一个数据都由你组成。#乐动你我,无处不乐#',
    'media' : '<img src="images/psb.jpeg" width="370" >',
    'like' : 25038,
    'comment' : 417
})


app.js


//var data=require('data');


//--------  公共函数

var g = function(id){ return document.getElementById(id);}
var getBodyW = function(){ return document.body.offsetWidth; };
var getBodyH = function(){ return document.body.offsetHeight; };
var getElTop = function(el){ return el.offsetTop+170; };

//--------  模版内容输出

//  分析归类数据
var list = {};  //  { year: { month : [ item ,item ] } }

data.sort(function(a,b){
    return new Date(a.date).getTime() > new Date(b.date).getTime();
})

//  格式化数据
for (var i = data.length - 1; i >= 0; i--) {

    var date = new Date(data[i].date);
    var year  = date.getFullYear();
    var month = date.getMonth()+1;
    var lunar = GetLunarDateString( date );

    if( !list[year] ){ list[year] = {}; }
    if( !list[year][month] ){ list[year][month] = []; }

    var item = data[i];
    item.lunar = lunar[0]+'<br>&nbsp;&nbsp;&nbsp;'+lunar[1];
    item.like_format = item.like < 10000 ? item.like : ( item.like / 10000 ).toFixed(1) + '万';

    list[year][month].push( item );
};


//  最终html内容
var html_scrubber = [];
var html_content  = [];

//  模版
var tpl_scrubber_year = g('tpl_scrubber_year').innerHTML.replace(/^\s*/,'').replace(/\s*$/,'');
var tpl_scrubber_month = g('tpl_scrubber_month').innerHTML.replace(/^\s*/,'').replace(/\s*$/,'');

var tpl_content_year = g('tpl_content_year').innerHTML.replace(/^\s*/,'').replace(/\s*$/,'');
var tpl_content_month = g('tpl_content_month').innerHTML.replace(/^\s*/,'').replace(/\s*$/,'');

//  构建时序和内容html
for (year in list) {

    var scrubber_month = [];
    var content_month = [];

    var isLeft = 0;

    for (month in list[year]) {
        scrubber_month.unshift(  tpl_scrubber_month.replace(/\{year\}/g,year).replace(/\{month\}/g,month) );

        for (var i = list[year][month].length - 1; i >= 0; i--) {
            var item = list[year][month][i];

            isLeft = isLeft ^ 1;
            content_month.unshift(
                ( (i==0) ?  '<div class="clear c_month" id="c_month_'+year+'_'+month+'"></div>'   : '' ) + tpl_content_month.replace(/\{year\}/g,year).replace(/\{month\}/g,month)
                    .replace(/\{lunar\}/g,item.lunar)
                    .replace(/\{date\}/g,item.date)
                    .replace(/\{intro\}/g,item.intro)
                    .replace(/\{media\}/g,item.media)
                    .replace(/\{like\}/g,item.like)
                    .replace(/\{comment\}/g,item.comment)
                    .replace(/\{like_format\}/g,item.like_format)
                    .replace(/\{leftOrRight\}/g, isLeft ? 'left' : 'right')
                    .replace(/\{isFirst\}/g, i == 0 ? 'c_item_first' : '')
            ) ;
        };

    };
    html_scrubber.unshift( tpl_scrubber_year.replace(/\{year\}/g,year).replace(/\{list\}/g,scrubber_month.join('') ) );

    html_content.unshift( tpl_content_year.replace(/\{year\}/g,year).replace(/\{list\}/g,content_month.join('') )  );
};

//  写入内容
g('scrubber').innerHTML = '<a href="javascript:;" onclick="scrollTopTo(0)">现在</a>'+html_scrubber.join('')+'<a href="javascript:;" onclick="scrollTopTo(getBodyH())">出生</a>';
g('content').innerHTML = html_content.join('')+ tpl_content_year.replace(/\{year\}/g,'出生').replace(/\{list\}/g,'')+'<div class="clear c_month" id="c_month_0_0"></div>'  ;



//--------  脚本处理

//  动画卷动
var  scrollTopTo = function( to ){
    var start =  document.body.scrollTop;
    fx( function( now , type ){  window.scroll(0,now); },start ,to );
}


//  展开时序
var expandScrubber = function( year,elem ){

    var years  = document.getElementsByClassName('s_year');
    var months = document.getElementsByClassName('s_month');

    var year_months = document.getElementsByClassName(year+'_month');

    //  清理所有年份的 cur 样式
    for (var i = years.length - 1; i >= 0; i--) {
        years[i].className = 's_year';
    };

    //  隐藏所有的月份
    for (var i = months.length - 1; i >= 0; i--) {
        months[i].style.display = 'none';
    };

    //  展现当前年份下所有的月份
    for (var i = year_months.length - 1; i >= 0; i--) {
        year_months[i].style.display = 'block';
    };

    //  设置当前年份的 cur 样式
    elem.className = 's_year cur';
}

//  高亮月份
var highlightMonth = function( year , month , elem ){

    var months = document.getElementsByClassName(year+'_month');
    for (var i = months.length - 1; i >= 0; i--) {
        months[i].className = months[i].className.replace('cur','');

    };
    elem.className = elem.className+' cur';
}

//  年份点击处理
var showYear = function(year,elem){
    expandScrubber(year ,elem);
    var top = getElTop( g('content_year_'+year) );
    scrollTopTo( top );
    //  滚动到当前年份的位置
}

//  月份点击处理
var showMonth = function( year , month ,elem ){
    var top = getElTop( document.getElementsByClassName('content_date_'+year+''+month)[0] );
    highlightMonth( year , month , elem );
    scrollTopTo( top );
}


//  根据窗口滚动条更新时序年份状态
var updateScrubberOnTop = function( top ){

    var years  = g('content').getElementsByClassName('c_year');
    var tops = [];

    for (var i = 0; i <years.length ; i++) {
        tops.push( years[i].offsetTop );
    };

    for(var i = 1; i <tops.length ; i++){

        if( top > tops[i-1] && top < tops[i] ){

            var year = years[i-1].innerHTML;

            expandScrubber(year,g('scrubber_year_'+year));
            return ;
        }
    }

}

//  根据窗口滚动条更新时序月份状态
var updateMonthOnTop = function( top ){

    var months  = g('content').getElementsByClassName('c_month');
    var tops = [];

    for (var i = 0; i <months.length ; i++) {
        tops.push( months[i].offsetTop );
    };

    for(var i = 1; i <tops.length ; i++){

        if( top > tops[i-1] && top < tops[i] ){

            var info  = months[i-1].id.split('_');
            var year  = info[2];
            var month = info[3];
            highlightMonth( year , month , g('scrubber_month_'+year+month) );

            return ;
        }
    }
}

//  滚动条事件处理; 定位时间
window.onscroll = function(){

    var top = document.body.scrollTop ;

    if( top > 200){
        g('scrubber').style.position = 'fixed';
        g('scrubber').style.left = (getBodyW()-960)/2+ 'px';
        g('scrubber').style.top  = '60px';
    }else{
        g('scrubber').style.position = '';
        g('scrubber').style.left =     '';
        g('scrubber').style.top  =     '';
    }

    //  更新时序状态
    updateScrubberOnTop( top );
    updateMonthOnTop( top );
}

//  窗口改变事件处理; 保持时序列表的位置
window.onresize = function(){
    window.onscroll();
}

fx.js


//  动画函数
var fx = function( fn , begin , end ){

    //  渐出特效
    fx.easeOut = function(t,b,c,d){
        return -c *(t /= d)*(t-2) + b;
    }

    var options = arguments[3] || {};
    var duration = options.duration || 500;
    var ease = options.ease || fx.easeOut;

    startTime = new Date().getTime();

    (function(){
        setTimeout(function(){
            timestamp = new Date().getTime() - startTime;
            fn( ease( timestamp,begin, ( end - begin),duration) , 'step' );

            if(duration <= timestamp){
                fn( end , 'end' );
            }else{
                setTimeout(arguments.callee,25);
            }
        },25)
    })();
}

GetLunarDay.js


var LunarDaysOfMonth = new Array

(

    0xd4a8, 0xd4a0, 0xda50, 0x5aa8, 0x56a0, 0xaad8, 0x25d0, 0x92d0, 0xc958, 0xa950, // 2001-2010

    0xb4a0, 0xb550, 0xb550, 0x55a8, 0x4ba0, 0xa5b0, 0x52b8, 0x52b0, 0xa930, 0x74a8, // 2011-2020

    0x6aa0, 0xad50, 0x4da8, 0x4b60, 0x9570, 0xa4e0, 0xd260, 0xe930, 0xd530, 0x5aa0, // 2021-2030

    0x6b50, 0x96d0, 0x4ae8, 0x4ad0, 0xa4d0, 0xd258, 0xd250, 0xd520, 0xdaa0, 0xb5a0, // 2031-2040

    0x56d0, 0x4ad8, 0x49b0, 0xa4b8, 0xa4b0, 0xaa50, 0xb528, 0x6d20, 0xada0, 0x55b0  // 2041-2050

);



// 数组LunarLeapYear存放农历2001年到2050年闰月的月份,如没有则为0,从高到低,每字节存两年

var LunarLeapYear = new Array

(

    0x40, 0x02, 0x07, 0x00, 0x50, // 2001-2010

    0x04, 0x09, 0x00, 0x60, 0x04, // 2011-2020

    0x00, 0x20, 0x60, 0x05, 0x00, // 2021-2030

    0x30, 0xb0, 0x06, 0x00, 0x50, // 2031-2040

    0x02, 0x07, 0x00, 0x50, 0x03  // 2041-2050

);





// 返回农历iLunarYear年的闰月月份,如没有则返回0

function GetLeapMonth(iLunarYear)

{

    var Leap = LunarLeapYear[(iLunarYear - 2001) >> 1];

    return (((iLunarYear - 2001) & 1) == 0) ? (Leap >> 4) : (Leap & 0x0f);

}



// 返回农历iLunarYer年iLunarMonth月的天数,结果是一个长整数

// 如果iLunarMonth不是闰月, 高字为0,低字为该月的天数

// 如果iLunarMonth是闰月, 高字为后一个月的天数,低字为前一个月的天数

function LunarMonthDays(iLunarYear, iLunarMonth){

    var High;

    var Low;

    var Bit;



    High = 0;

    Low = 29;

    Bit = 16 - iLunarMonth;

    if ((iLunarMonth > GetLeapMonth(iLunarYear)) && (GetLeapMonth(iLunarYear) > 0))  Bit--;

    if ((LunarDaysOfMonth[iLunarYear - 2001] & (1 << Bit)) > 0)  Low++;

    if (iLunarMonth == GetLeapMonth(iLunarYear))

    {

        High = ((LunarDaysOfMonth[iLunarYear - 2001] & (1 << (Bit-1))) > 0) ?  30 : 29;

    }



    return Low + (High << 16);

}



// 返回农历iLunarYear年的总天数

function LunarYearDays(iLunarYear)

{

    var Days;

    var tmp;



    Days = 0;

    for (var i=1; i <= 12; i++)

    {

        tmp = LunarMonthDays(iLunarYear, i);

        Days = Days + ((tmp >> 16) & 0xffff); //取高位

        Days = Days + (tmp & 0xffff); //取低位

    }



    return Days;

}



// 将农历iLunarYear年格式化成天干地支记年法表示的字符串

function FormatLunarYear(iLunarYear)

{

    var szText1 = new String("甲乙丙丁戊己庚辛壬癸");

    var szText2 = new String("子丑寅卯辰巳午未申酉戌亥");

    var strYear;



    strYear = szText1.substr((iLunarYear - 4) % 10, 1);

    strYear = strYear + szText2.substr((iLunarYear - 4) % 12, 1);



    return strYear + "年";

}



// 将农历iLunarMonth月格式化成农历表示的字符串

function FormatLunarMonth(iLunarMonth)

{

    var szText = new String("正二三四五六七八九十");

    var strMonth;



    if (iLunarMonth <= 10)

    {

        strMonth = szText.substr(iLunarMonth - 1, 1);

    }

    else if (iLunarMonth == 11) strMonth = "十一";

    else strMonth = "十二";



    return strMonth + "月";

}



// 将农历iLunarDay日格式化成农历表示的字符串

function FormatLunarDay(iLunarDay)

{

    var szText1 = new String("初十廿三");

    var szText2 = new String("一二三四五六七八九十");

    var strDay;

    if ((iLunarDay != 20) && (iLunarDay != 30))

    {

        strDay = szText1.substr((iLunarDay - 1) / 10, 1) + szText2.substr((iLunarDay - 1) % 10, 1);

    }

    else if (iLunarDay != 20)

    {

        strDay = szText1.substr(iLunarDay / 10, 1) + "十";

    }

    else

    {

        strDay = "二十";

    }



    return strDay;

}



// 将公历日期转换为农历日期,返回农历表示的字符串

function GetLunarDateString(SolarDate)

{

    var tmp;

    var iLunarYear;

    var iLunarMonth;

    var iLunarDay;

    var Leap = false;

    var MinMilli = 1000 * 60;

    var HrMilli = MinMilli * 60;

    var DyMilli = HrMilli * 24;



    // 从2001年1月1日算起,给定的公历日期已经过去的天数

    // 11323是1970年1月1日到2001年1月1日之间的天数,因为Date是从1970年1月1日作为起点的

    var iSpanDays = Math.round(SolarDate.getTime() / DyMilli) - 11323;



    // 公历2001年1月24日为农历2001年正月初一,差23天

    if (iSpanDays < 23)

    {

        iYear = 2000;

        iLunarMonth = 12;

        iLunarDay = iSpanDays + 7;

    }

    else

    {

        // 从农历2001年正月初一算起

        iSpanDays = iSpanDays - 23;

        iLunarYear = 2001;

        iLunarMonth = 1;

        iLunarDay = 1;



        // 计算农历年

        tmp = LunarYearDays(iLunarYear);

        while (iSpanDays >= tmp)

        {

            iSpanDays -= tmp;

            iLunarYear++;

            tmp = LunarYearDays(iLunarYear);

        }



        // 计算农历月

        tmp = LunarMonthDays(iLunarYear, iLunarMonth) & 0xffff; //取低字

        while (iSpanDays >= tmp)

        {

            iSpanDays -= tmp;

            if (iLunarMonth == GetLeapMonth(iLunarYear))  // 该年该月闰月

            {

                tmp = LunarMonthDays(iLunarYear, iLunarMonth) >> 16; //取高字

                if (iSpanDays < tmp)

                {

                    Leap = (tmp > 0) ? true : false;  // 闰月的后个月?

                    break;

                }

                iSpanDays = iSpanDays - tmp;

            }



            iLunarMonth++;

            tmp = LunarMonthDays(iLunarYear,iLunarMonth) & 0xffff; //取低字

        }



        // 计算农历日

        iLunarDay += iSpanDays;

    }



    return FormatLunarDay(iLunarDay);

}

//调用方法举例如下:

//var today= new Date();   // 今天是2004-3-5

//var str = GetLunarDateString(today);

//结果是 “甲申年二月十五”。

运行结果如图:

这里写图片描述


这里写图片描述


这里写图片描述


本文转载:CSDN博客