首页 > 代码库 > JS时间轴效果(类似于qq空间时间轴效果)

JS时间轴效果(类似于qq空间时间轴效果)

 

2013-11-04 23:51 by 空智, 4041 阅读, 15 评论, 收藏, 编辑

       在上一家公司写了一个时间轴效果,今天整理了下,感觉有必要写一篇博客出来 给大家分享分享 当然代码还有很多不足的地方,希望大家多指点指点下,此效果类似于QQ空间或者人人网空间时间轴效果,当时也是为了需求 研究了下qq空间逻辑(当然JS代码压缩了肯定看不到的),只是当时研究了下他们HTML结构和css结构,所以仿照他们那种逻辑自己也写了一个出来。先来看看是个什么样的吧!如下图所示:

技术分享

需求分析:左侧是一个时间列表 右侧是一个时间控制抽,当时的需求是这样的:默认页面一打开 只加载当前年份所有列表加载出来 当前年份的控制轴展开出来,默认的焦点在最近的月份,如上图在当前的10月份或者下图的12月份,当滚动条滚动的时候再继续判断 如果左侧滚动到几月份的时候 那么右侧控制抽当前的焦点也在几月份,当滚动到上一个年份的时候 那么当前的年份控制轴收缩起来 上一个年份控制轴展开出来,如下图所示:

 技术分享

当我们点击某一年份的时候 滚动到当前的年份,当我点击某一年中某一月份的时候 滚动到当前年份中对应的月份上来。

当然下面的代码我是用到的是淘宝的KISSY框架  当然如果改成Jquery框架也是一样的,没有很大的差别 只是用了一下"延迟加载"和一些选择器而已,首先我们如果要做成这样的话 要知道有2个请求 一个是左侧列表请求返回的数据 一个是右侧的年份和月份返回的数据 下面我们可以先来看看 开发给我当时返回的数据格式是个什么样的,

左侧列表的JSON数据如下图:

技术分享

默认情况下是最近年份 当我滚动到2012年时候 再继续发个2012年的请求 把2012年的相对应的数据渲染出来,同理2011年也一样.

再来看看年份和月份的JSON数据吧 如下图:

技术分享

下面我一步步来分析下 我当时的做法:

1. 首先我需要HTML结构 如下图所示:

<div class="tao-allMonth-w990"> 
        <div class="tao-video-left J_Video_Left" id="J_Video_Left"></div> 
        <div class="tao-year-right"> 
            <div class="mod-timelinenav"> 
                <ul id="timelinenavpanel" class="timelinenav-panel isScroll"></ul> 
            </div> 
        </div> 
    </div>

其中 id="J_Video_Left" 和 id="timelinenavpanel" 在初始化的时候 是可以配置的 也就是说 他们叫什么名字并不重要,依赖于这个HTML结构。

2. 依赖于css代码 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
<style>
     .tao-allMonth-w990 {width: 990px;margin: 100px auto 0;overflow: hidden;    }
    .tao-video-left {float:left;width: 620px;overflow: hidden;}
    .tao-video-block {width: 620px;overflow: hidden;}
    .tao-header-title {width: 100%;height: 26px;overflow: hidden;}
    .tao-header-title {color: #FF6600;font-family: "Microsoft yahei";font-size: 18px;font-weight: 700;padding-left: 42px;}
    .tao-dottle-top {width: 10px;height: 40px;margin-left: 68px;background: none repeat scroll 0 0 #FFCC99;overflow: hidden;    }
    .tao-video-content {position: relative;width: 620px;overflow: hidden;}
    .tao-video-content .addBlock {
        background: none repeat scroll 0 0 #FFCC99;
        height: 16px;
        left: 68px;
        position: absolute;
        width: 10px;
    }
    .left-date {
        color: #FF6600;
        float: left;
        font-family: "Microsoft yahei";
        font-size: 14px;
        height: 20px;
        line-height: 20px;
        margin-top: 18px;
        overflow: hidden;
        width: 60px;
    }
    .left-date span {
        float: left;
    }
    .tao-video-content .tao-line {
        background: url("http://img02.taobaocdn.com/tps/i2/T1je8uXEBgXXagEfc2-10-205.png") no-repeat scroll 0 0 rgba(0, 0, 0, 0);
        display: inline;
        float: left;
        height: 205px;
        margin: 24px 0 0 8px;
        overflow: hidden;
        width: 10px;
    }
    .tao-inner-content {
        background: url("http://img03.taobaocdn.com/tps/i3/T16VXtXBNiXXXPeW.X-519-190.png") no-repeat scroll 0 0 rgba(0, 0, 0, 0);
        display: inline;
        float: left;
        height: 190px;
        margin: 0 0 0 20px;
        overflow: hidden;
        width: 519px;
    }
    .tao-inner-block {
        height: 130px;
        margin: 30px 0 0 40px;
        overflow: hidden;
        width: 450px;
    }
    .tao-inner-block .inner-left {
        float: left;
        height: 130px;
        overflow: hidden;
        width: 230px;
    }
    .inner-left .alink {
        display: block;
        height: 130px;
        overflow: hidden;
        position: relative;
        width: 230px;
    }
    .inner-left .alink img {
        display: block;
        height: 130px;
        width: 230px;
    }
    .tao-inner-block .icon-player {
        background: url("http://img02.taobaocdn.com/tps/i2/T1J5FFXy8cXXaiphQj-60-145.png") no-repeat scroll 0 -40px rgba(0, 0, 0, 0);
        height: 50px;
        left: 10px;
        overflow: hidden;
        position: absolute;
        top: 68px;
        width: 50px;
        z-index: 10;
    }
    .inner-right {
        float: right;
        height: 130px;
        width: 202px;
    }
    .inner-date {
        color: #666666;
        font-family: "Tahoma";
    }
    .inner-title {
        height: 22px;
        line-height: 22px;
        margin-top: 5px;
        overflow: hidden;
        width: 202px;
    }
    .inner-title a {
        color: #333333;
        font-family: "Microsoft yahei";
        font-size: 18px;
        font-weight: 700;
    }
    .inner-title a:hover {
        color: #FF1155;
        text-decoration: none;
    }
    .inner-content {
        color: #999999;
        line-height: 18px;
        margin-top: 12px;
    }
    .tao-year-right {
        float: right;
        overflow: hidden;
        width: 311px;
    }
    .tao-year-right .mod-fixed {
        overflow: hidden;
        position: fixed;
        top: 0;
        width: 60px;
        z-index: 10;
    }
    .mod-timelinenav {
        margin-top: 20px;
    }
    .mod-timelinenav .yearlink {
        display: inline-block;
    }
    .mod-timelinenav a {
        display: inline-block;
    }
    .mod-timelinenav a:hover {
        text-decoration: none;
    }
    .mod-timelinenav .yearlink, .mod-timelinenav .monthlink {
        border-left: 10px solid #74C2FA;
        color: #7FCCFF;
        font-family: "Tahoma";
        line-height: 20px;
        padding-left: 8px;
    }
    .mod-timelinenav .norecord {
        display: none;
    }
    .mod-timelinenav .active .yearlink, .mod-timelinenav .active .monthlink {
        border-left: 10px solid #0099FF;
        color: #0099FF;
        font-family: "Tahoma";
        line-height: 20px;
        padding-left: 8px;
    }
    .mod-timelinenav .active .monthlink {
        color: #7FCCFF;
    }
    .mod-timelinenav .highlight .monthlink {
        color: #0099FF;
        font-family: "Tahoma";
    }
    .mod-timelinenav .active .timelinenav-mpanel {
        display: block;
    }
    .mod-timelinenav .timelinenav-mpanel {
        display: none;
    }
    .timelinenav-panel {
        overflow: hidden;
        width: 60px;
    }
    .timelinenav-panel li {
        margin: 1px 0;
    }
    .timelinenav-panel li.active, .timelinenav-panel li.active .timelinenav-mpanel li {
        margin: 0;
    }
    .hot-footage {
        bottom: 0;
        overflow: hidden;
        position: fixed;
        width: 311px;
        z-index: 8;
    }
    .hot-footage .dottle {
        border-top: 1px solid #CCCCCC;
    }
    .hot-title {
        margin-top: 12px;
    }
    .hot-icon {
        background: none repeat scroll 0 0 #FF6600;
        float: left;
        height: 28px;
        margin-top: 10px;
        overflow: hidden;
        width: 4px;
    }
    .hot-title h3 {
        color: #333333;
        font-family: "Microsoft yahei";
        font-size: 30px;
        font-weight: 500;
        padding-left: 10px;
    }
    .hot-list {
        margin-top: 5px;
        overflow: hidden;
        width: 311px;
    }
    .hot-list li {
        display: inline;
        float: left;
        height: 150px;
        margin: 5px 10px 0 0;
        overflow: hidden;
        width: 150px;
    }
    .hot-list li.last {
        margin-right: 0;
    }
    .hot-list li a {
        display: block;
        height: 100px;
        overflow: hidden;
        position: relative;
        width: 150px;
    }
    .hot-list .icon-player {
        background: url("http://img02.taobaocdn.com/tps/i2/T1J5FFXy8cXXaiphQj-60-145.png") no-repeat scroll 0 -40px rgba(0, 0, 0, 0);
        height: 50px;
        left: 10px;
        overflow: hidden;
        position: absolute;
        top: 40px;
        width: 50px;
        z-index: 10;
    }
    .hot-date {
        color: #666666;
        font-family: "Tahoma";
        height: 18px;
        line-height: 18px;
        margin-top: 5px;
    }
    .hot-desc a:hover {
        text-decoration: none;
    }
  </style>

 3. 当然更依赖于kissy哦 要引入kissy:<script src="http://a.tbcdn.cn/??s/kissy/1.2.0/kissy-min.js"></script>

 现在框架已经搭建好了,接下来我来分析下 当时我写的JS代码。首先我想渲染左侧年份列表出来 及右侧控制轴渲染出来 如下图:

  技术分享技术分享

所以上面的代码是渲染年份列表的 如下:

/* 
             * 发jsonp请求 
             * 1.渲染列表中的所有年份HTML出来
             * 2.把控制轴上的所有年份及月份及条目列表中的年份渲染出来
             */
             S.jsonp(_config.year_url + "&timestamp="+S.now(),function(data){
                _renderYear(data);
             });
             function _renderYear(data) {
                if(data.isSuccess) {
                    var yearlists = data.list,
                        yearHTML = ‘‘,
                        liHTML = ‘‘;
                    /*
                     * 渲染列表中的所有年份HTML出来
                     */
                     for(var i = 0, ilen = yearlists.length; i < ilen; i+=1) {
                        yearHTML += ‘<div class="J_Year_Month">‘+
                                        ‘<div class="tao-header-title J_Header_Title">‘+
                                            ‘<span data-year="‘+yearlists[i].year+‘" class="J_Year">‘+yearlists[i].year+‘<i>年</i></span>‘+
                                        ‘</div>‘ + 
                                        ‘<div class="tao-dottle-top"></div>‘ + 
                                        ‘<div class="J_Video_Block"></div>‘ + 
                                    ‘</div>‘;
                     }
                     var recentlyYear = yearlists[0].year;
                     D.html(D.get(_config.videoContainer),yearHTML);
                     /*
                      * 把控制轴上的所有年份渲染出来
                      */
                     for(i = 0,itemLen = yearlists.length; i < itemLen; i++){
                        liHTML += ‘<li data-year="‘+yearlists[i].year+‘" class="itemList">‘ + 
                                     ‘<a class="yearlink" href="http://www.mamicode.com/#">‘+yearlists[i].year+‘年</a>‘ +
                                     ‘<ul class="timelinenav-mpanel"></ul>‘ +  
                                   ‘</li>‘;
                     }
                     D.html(D.get(_config.listContainer),liHTML,false,function(){
                        D.addClass(D.get(_config.listContainer + " li"),_config.activeCls);
                        D.attr(D.get(_config.listContainer + " li"),{"index":"1"});
                     });

                     /*
                      * 分别渲染各个年份中的月份
                      */
                     var monthContainers = D.query(".timelinenav-mpanel"); 
                     for(var m = 0, mlen = monthContainers.length; m < mlen; m+=1) {
                        var ulHTML = "";
                        for(var k = 0,subItems = yearlists[m].month.length; k < subItems; k+=1){
                            ulHTML += ‘<li data-year="‘+yearlists[m].year+‘" data-month="‘+yearlists[m].month[k]+‘" class="itemHover">‘ + 
                                         ‘<a class="monthlink" href="http://www.mamicode.com/#">‘+yearlists[m].month[k]+‘月</a>‘ +
                                       ‘</li>‘;
                        }
                        D.html(monthContainers[m],ulHTML,false,function(){
                            
                            var headerTitle = D.query(".J_Year"),
                                itemLists = D.query(".itemList"),
                                videoBlocks = D.query(".J_Video_Block");
                            // 默认时候 当前年份 最近月份高亮
                            D.addClass(D.get(".itemHover"),_config.highlightCls);
                        });
                     }

4. 接着发请求 把左侧列表中最近年份 下的所有月份渲染出来 如下代码可以实现:

var self = this,
                _config = self.config;
            var allYears = D.query(".J_Year_Month");
            
            S.each(allYears,function(everyYear,index){
                var jYear = D.get(".J_Year",everyYear),
                    jDataYear = D.attr(jYear,"data-year"),
                    jTextArea = D.get(".J_Video_Block",everyYear);
                S.jsonp(_config.list_url+"&group="+jDataYear+"&timestamp="+S.now(),function(data){
                    if(data.isSuccess){
                        var dataLists = data.list,
                            dataContainer = "";
                        for(var x=0,xlen=dataLists.length; x<xlen; x+=1){
                            var tempGroupId = dataLists[x].group_id;
                            dataContainer +=‘<div class="tao-video-content">‘+
                                                ‘<div class="addBlock"></div>‘ +
                                                ‘<div class="left-date" videoMonth="‘+tempGroupId.substring(4,6)+‘">‘+
                                                    ‘<span><i class="J_Month" M_year="‘+tempGroupId.substring(0,4)+‘">‘+tempGroupId.substring(4,6)+‘</i>月</span>‘+
                                                    ‘<span><i class="J_Day">‘+tempGroupId.substring(6,8)+‘</i>日</span>‘+
                                                ‘</div>‘+
                                                ‘<div class="tao-line"></div>‘+
                                                ‘<div class="tao-inner-content">‘+
                                                    ‘<div class="tao-inner-block">‘+
                                                        ‘<div class="inner-left">‘+
                                                            ‘<a href="http://bbs.hitao.com/apps.php?q=tvshow&m=detail_new&tid=‘+dataLists[x].tid+‘" class="alink">‘+
                                                                ‘<img src="http://www.mamicode.com/‘+dataLists[x].video_pic.replace("/0","/1")+‘" >‘+
                                                                ‘<span class="icon-player"></span>‘+
                                                            ‘</a>‘+
                                                        ‘</div>‘+
                                                        ‘<div class="inner-right">‘+
                                                            ‘<p class="inner-date">‘+tempGroupId.substring(0,4)+‘-‘+tempGroupId.substring(4,6)+‘-‘+tempGroupId.substring(6,8)+‘</p>‘+
                                                            ‘<p class="inner-title">‘ +
                                                                ‘<a href="http://bbs.hitao.com/apps.php?q=tvshow&m=detail_new&tid=‘+dataLists[x].tid+‘">‘+dataLists[x].subject+‘</a>‘+
                                                            ‘</p>‘+
                                                            ‘<div class="inner-content">‘+dataLists[x].content+‘</div>‘+
                                                        ‘</div>‘+
                                                    ‘</div>‘+
                                                ‘</div>‘+
                                             ‘</div>‘;
                        }
                        if(flag == ‘hover‘) {
                            (new DataLazyload(everyYear, {diff: 200})).addCallback(everyYear, function(){
                                self._isDelayLoad(jTextArea,dataContainer,index);
                            });
                        }

我上面的代码也有个小缺点 就是说页面一打开的时候 联系发了四个请求 把所有年份都渲染出来 但是数据并没有到页面上来 还是以前的逻辑 当滚动条滚动到离还有200像素的时候 再把数据渲染到页面上来。

5. 接着再做了以下事情:

     1.  列表中的年份和控制轴中的年份相等时候 控制轴的年份展开。

   2.  当滚动到列表中年份中的月份时候 对应的控制轴月份也要相应的变化(如高亮等),随着鼠标滚动。

   3.  点击控制轴任一年份时候 滚动到条目列表中相对应的年份来.

代码如下:

   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
var self = this,
                _config = self.config,
                _cache = self.cache;
 
            D.html(jTextArea,dataContainer,false,function(){
                var itemLists = D.query(_config.listContainer + " .itemList"),
                    itemHover = D.query(".itemHover",itemLists[index]),
                    jmonths = D.query(".J_Month",jTextArea[index]),
                    headerTitle = D.query(".J_Year");
                // 默认时候 当前年份 最近月份高亮
                D.addClass(D.get(".itemHover"),_config.highlightCls);
     
                var storage = function(itemFChar){
                    for(var i = 0, ilen = itemHover.length; i < ilen; i+=1){
                         var itemMonth = D.attr(itemHover[i],"data-month");
                         if(itemMonth == itemFChar){
                            KISSY.all(itemHover[i]).addClass(_config.highlightCls).siblings().removeClass(_config.highlightCls);
                        }
                    }
                };
                E.on(window,‘scroll‘,function(){
                    if(D.hasClass(D.get(_config.listContainer),‘isScroll‘)){
                        var wTop = D.offset(window).top;
                        /*** 列表中的年份和控制轴中的年份相等时候 控制轴的年份展开 ***/
                        for(var m=0,mlen=headerTitle.length; m<mlen; m+=1){
                            var headerTop = D.offset(headerTitle[m]).top,
                                headAttr = D.attr(headerTitle[m],"data-year"),
                                itemAttr = D.attr(itemLists[m],"data-year");
                            if(headerTop <= wTop){
                                if(headAttr == itemAttr){
                                    KISSY.all(itemLists[m]).addClass(_config.activeCls).siblings().removeClass(_config.activeCls);
                                }
                            }
                        }
                        /*** 当滚动到列表中年份中的月份时候 对应的控制轴月份也要相应的变化(如高亮等) **/
                        for(var nn = 0, nlen = jmonths.length; nn < nlen; nn+=1){
                            var jmonthTop = D.offset(jmonths[nn]).top;
                            if(jmonthTop <= wTop){
                                 
                                var itemVal = D.html(jmonths[nn]),
                                // 转换02 -> 2
                                itemFChar = itemVal.substring(0,1);
                                if(itemFChar == 0){
                                    itemFChar = itemVal.substring(1,2);
                                }else{
                                    itemFChar = itemVal.substring(0,2);
                                }
                                storage(itemFChar);
                            }
                        }
                    }
                });
                // 点击控制轴任一年份时候 滚动到条目列表中相对应的年份来
               var  itemLists = D.query(_config.listContainer + " .itemList");
               S.each(itemLists,function(item,index){
                   var innerIndex;
                   E.on(item,‘click‘,function(e){
                       e.preventDefault();
                       e.halt();
                       innerIndex = index;
                       var scrollTimer,
                           DELAY = 0.3;
                       !D.hasClass(KISSY.all(this),_config.activeCls) && KISSY.all(this).addClass(_config.activeCls).siblings().removeClass(_config.activeCls);
                        
                       if(!D.hasClass(KISSY.all(this),"isClick")){
                           D.addClass(KISSY.all(this),"isClick");
                       }
                       var curThis = KISSY.all(this);
                       // 删除类
                       D.hasClass(D.get(_config.listContainer),‘isScroll‘) && D.removeClass(D.get(_config.listContainer),‘isScroll‘);
                       var headerTop = D.offset(headerTitle[index]).top;
                       scrollTimer && scrollTimer.cancel();
                       scrollTimer = S.later(function(){
                            KISSY.all("html,body").animate({"scrollTop":headerTop},DELAY,‘easeBothStrong‘,function(){
                                D.removeClass(D.query(".itemHover"),_config.highlightCls);
                                !D.hasClass(D.get(".itemHover",curThis),_config.highlightCls) && D.addClass(D.get(".itemHover",curThis),_config.highlightCls);
                                !D.hasClass(D.get(_config.listContainer),‘isScroll‘) && D.addClass(D.get(_config.listContainer),‘isScroll‘);
                            });
                        },DELAY);
                        _config.yearCallback && S.isFunction(_config.yearCallback) && _config.yearCallback();
                        self._clickMenu(itemLists,innerIndex);
                   });
                   if(innerIndex == undefined){
                      innerIndex = 0;
                      self._clickMenu(itemLists,innerIndex);
                   }
               });

 6. 最后 点击控制轴当前年份中的月份时候 滚动到当前的月份的地方。代码如下:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 点击控制轴当前年份中的月份时候 滚动到当前的月份的地方。
            var itemHovers = D.query(".itemHover",KISSY.all(itemLists[innerIndex]));
            S.each(itemHovers,function(itemHover,curIndex){
                E.on(itemHover,‘click‘,function(e){
                     
                    e.halt();
                    var itemMonth = D.attr(KISSY.all(itemHover),"data-month");
                    var tempArr = [],
                        scrollTimer,
                        DELAY = 0.1;
                    console.log(itemMonth);
                    var curMonths = D.query(".left-date",D.query(".J_Year_Month")[innerIndex]);
                     // 删除类
                    D.hasClass(D.get(_config.listContainer),‘isScroll‘) && D.removeClass(D.get(_config.listContainer),‘isScroll‘);
                    KISSY.all(‘.itemHover‘).removeClass(_config.highlightCls);
                    KISSY.all(this).addClass(_config.highlightCls).siblings().removeClass(_config.highlightCls);
                    for(var i=0; i<curMonths.length; i+=1){
                        var itemVal = D.attr(curMonths[i],"videoMonth");
                        // 转换02 -> 2
                        var itemFChar = itemVal.substring(0,1);
                        if(itemFChar == 0){
                            itemFChar = itemVal.substring(1,2);
                        }else{
                            itemFChar = itemVal.substring(0,2);
                        }
                        tempArr.push(itemFChar);
                    }
                    for(var j=0; j<tempArr.length; j+=1){
                        var tempV = tempArr[j];
                        if(itemMonth == tempArr[j]){
                            var mtop = D.offset(curMonths[j]).top;
                            scrollTimer && scrollTimer.cancel();
                            scrollTimer = S.later(function(){
                                KISSY.all("html,body").animate({"scrollTop":mtop},DELAY,‘easeBothStrong‘,function(){
                                    !D.hasClass(D.get(_config.listContainer),‘isScroll‘) && D.addClass(D.get(_config.listContainer),‘isScroll‘);
                                });
                            },DELAY);
                            break; // 此break是当数组里面的月份有多个相同的时候 只取第一个月份
                        }
                    }
                    _config.monthCallback && S.isFunction(_config.monthCallback) && _config.monthCallback();

 

  综合以上 所有JS代码如下:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
KISSY.add(‘timeline/nav‘,function(S,DataLazyload){
    var D = S.DOM,
        E = S.Event;
 
    function TimeLineNav() {
 
        this.config = {
            year_url       :‘http://bbs.hitao.com/apps.php?q=tvshow&m=video_years‘,    //所有年份URL
            list_url       :‘http://bbs.hitao.com/apps.php?q=tvshow&m=video_group‘,    // 时间轴list列表 URL
            delay          : 100,                                                      // 延迟time
            highlightCls   :‘highlight‘,                                               // 高亮类
            fixedCls       :‘mod-fixed‘,                                               // fixed类
            activeCls      :‘active‘,                                                  // 当前active class
            videoContainer :‘#J_Video_Left‘,                                           // 左侧视频容器
            listContainer  :‘#timelinenavpanel‘,                                       // 控制轴容器
            yearCallback   : null,                                                     // 点击某一项年份时的回调函数
            monthCallBack  : null                                                      // 点击某一项月份时候回调
        };
 
        this.cache = {
             
        };
    }
    TimeLineNav.prototype = {
        init: function(options) {
            this.config = S.augment(this.config,options || {});
            var self = this,
                _config = self.config;
            /*
             * 发jsonp请求
             * 1.渲染列表中的所有年份HTML出来
             * 2.把控制轴上的所有年份及月份及条目列表中的年份渲染出来
             */
             S.jsonp(_config.year_url + "&timestamp="+S.now(),function(data){
                _renderYear(data);
             });
             function _renderYear(data) {
                if(data.isSuccess) {
                    var yearlists = data.list,
                        yearHTML = ‘‘,
                        liHTML = ‘‘;
                    /*
                     * 渲染列表中的所有年份HTML出来
                     */
                     for(var i = 0, ilen = yearlists.length; i < ilen; i+=1) {
                        yearHTML += ‘<div class="J_Year_Month">‘+
                                        ‘<div class="tao-header-title J_Header_Title">‘+
                                            ‘<span data-year="‘+yearlists[i].year+‘" class="J_Year">‘+yearlists[i].year+‘<i>年</i></span>‘+
                                        ‘</div>‘ +
                                        ‘<div class="tao-dottle-top"></div>‘ +
                                        ‘<div class="J_Video_Block"></div>‘ +
                                    ‘</div>‘;
                     }
                     var recentlyYear = yearlists[0].year;
                     D.html(D.get(_config.videoContainer),yearHTML);
                     /*
                      * 把控制轴上的所有年份渲染出来
                      */
                     for(i = 0,itemLen = yearlists.length; i < itemLen; i++){
                        liHTML += ‘<li data-year="‘+yearlists[i].year+‘" class="itemList">‘ +
                                     ‘<a class="yearlink" href="http://www.mamicode.com/#">‘+yearlists[i].year+‘年</a>‘ +
                                     ‘<ul class="timelinenav-mpanel"></ul>‘
                                   ‘</li>‘;
                     }
                     D.html(D.get(_config.listContainer),liHTML,false,function(){
                        D.addClass(D.get(_config.listContainer + " li"),_config.activeCls);
                        D.attr(D.get(_config.listContainer + " li"),{"index":"1"});
                     });
 
                     /*
                      * 分别渲染各个年份中的月份
                      */
                     var monthContainers = D.query(".timelinenav-mpanel");
                     for(var m = 0, mlen = monthContainers.length; m < mlen; m+=1) {
                        var ulHTML = "";
                        for(var k = 0,subItems = yearlists[m].month.length; k < subItems; k+=1){
                            ulHTML += ‘<li data-year="‘+yearlists[m].year+‘" data-month="‘+yearlists[m].month[k]+‘" class="itemHover">‘ +
                                         ‘<a class="monthlink" href="http://www.mamicode.com/#">‘+yearlists[m].month[k]+‘月</a>‘ +
                                       ‘</li>‘;
                        }
                        D.html(monthContainers[m],ulHTML,false,function(){
                             
                            var headerTitle = D.query(".J_Year"),
                                itemLists = D.query(".itemList"),
                                videoBlocks = D.query(".J_Video_Block");
                            // 默认时候 当前年份 最近月份高亮
                            D.addClass(D.get(".itemHover"),_config.highlightCls);
                        });
                     }
                      
                    self._query(‘hover‘);
                }else {
                    return;
                }
             }
            /*
             * 1.滚动条先滚动 当离顶部距离差距不大的时候 使右侧菜单固定在顶部20px;
             */
            var timelineTop = D.offset(".mod-timelinenav").top,
                scrollTimer;
            E.on(window,‘scroll‘,function(){
                scrollTimer && scrollTimer.cancel();
                scrollTimer = S.later(function(){
                    var windowTop = D.offset(window).top;
                    if(timelineTop <=windowTop){
                        D.addClass(".mod-timelinenav","mod-fixed");
                    }else{
                        D.removeClass(".mod-timelinenav","mod-fixed");
                    }
                },_config.delay);
            });
             
        },
        _query: function(flag) {
            var self = this,
                _config = self.config;
            var allYears = D.query(".J_Year_Month");
             
            S.each(allYears,function(everyYear,index){
                var jYear = D.get(".J_Year",everyYear),
                    jDataYear = D.attr(jYear,"data-year"),
                    jTextArea = D.get(".J_Video_Block",everyYear);
                S.jsonp(_config.list_url+"&group="+jDataYear+"&timestamp="+S.now(),function(data){
                    if(data.isSuccess){
                        var dataLists = data.list,
                            dataContainer = "";
                        for(var x=0,xlen=dataLists.length; x<xlen; x+=1){
                            var tempGroupId = dataLists[x].group_id;
                            dataContainer +=‘<div class="tao-video-content">‘+
                                                ‘<div class="addBlock"></div>‘ +
                                                ‘<div class="left-date" videoMonth="‘+tempGroupId.substring(4,6)+‘">‘+
                                                    ‘<span><i class="J_Month" M_year="‘+tempGroupId.substring(0,4)+‘">‘+tempGroupId.substring(4,6)+‘</i>月</span>‘+
                                                    ‘<span><i class="J_Day">‘+tempGroupId.substring(6,8)+‘</i>日</span>‘+
                                                ‘</div>‘+
                                                ‘<div class="tao-line"></div>‘+
                                                ‘<div class="tao-inner-content">‘+
                                                    ‘<div class="tao-inner-block">‘+
                                                        ‘<div class="inner-left">‘+
                                                            ‘<a href="http://bbs.hitao.com/apps.php?q=tvshow&m=detail_new&tid=‘+dataLists[x].tid+‘" class="alink">‘+
                                                                ‘<img src="http://www.mamicode.com/‘+dataLists[x].video_pic.replace("/0","/1")+‘" alt="">‘+
                                                                ‘<span class="icon-player"></span>‘+
                                                            ‘</a>‘+
                                                        ‘</div>‘+
                                                        ‘<div class="inner-right">‘+
                                                            ‘<p class="inner-date">‘+tempGroupId.substring(0,4)+‘-‘+tempGroupId.substring(4,6)+‘-‘+tempGroupId.substring(6,8)+‘</p>‘+
                                                            ‘<p class="inner-title">‘ +
                                                                ‘<a href="http://bbs.hitao.com/apps.php?q=tvshow&m=detail_new&tid=‘+dataLists[x].tid+‘">‘+dataLists[x].subject+‘</a>‘+
                                                            ‘</p>‘+
                                                            ‘<div class="inner-content">‘+dataLists[x].content+‘</div>‘+
                                                        ‘</div>‘+
                                                    ‘</div>‘+
                                                ‘</div>‘+
                                             ‘</div>‘;
                        }
                        if(flag == ‘hover‘) {
                            (new DataLazyload(everyYear, {diff: 200})).addCallback(everyYear, function(){
                                self._isDelayLoad(jTextArea,dataContainer,index);
                            });
                        }
                    }else {
                        return;
                    }
                });
                 
            });
        },
        _isDelayLoad: function(jTextArea,dataContainer,index) {
            var self = this,
                _config = self.config,
                _cache = self.cache;
 
            D.html(jTextArea,dataContainer,false,function(){
                var itemLists = D.query(_config.listContainer + " .itemList"),
                    itemHover = D.query(".itemHover",itemLists[index]),
                    jmonths = D.query(".J_Month",jTextArea[index]),
                    headerTitle = D.query(".J_Year");
                // 默认时候 当前年份 最近月份高亮
                D.addClass(D.get(".itemHover"),_config.highlightCls);
     
                var storage = function(itemFChar){
                    for(var i = 0, ilen = itemHover.length; i < ilen; i+=1){
                         var itemMonth = D.attr(itemHover[i],"data-month");
                         if(itemMonth == itemFChar){
                            KISSY.all(itemHover[i]).addClass(_config.highlightCls).siblings().removeClass(_config.highlightCls);
                        }
                    }
                };
                E.on(window,‘scroll‘,function(){
                    if(D.hasClass(D.get(_config.listContainer),‘isScroll‘)){
                        var wTop = D.offset(window).top;
                        /*** 列表中的年份和控制轴中的年份相等时候 控制轴的年份展开 ***/
                        for(var m=0,mlen=headerTitle.length; m<mlen; m+=1){
                            var headerTop = D.offset(headerTitle[m]).top,
                                headAttr = D.attr(headerTitle[m],"data-year"),
                                itemAttr = D.attr(itemLists[m],"data-year");
                            if(headerTop <= wTop){
                                if(headAttr == itemAttr){
                                    KISSY.all(itemLists[m]).addClass(_config.activeCls).siblings().removeClass(_config.activeCls);
                                }
                            }
                        }
                        /*** 当滚动到列表中年份中的月份时候 对应的控制轴月份也要相应的变化(如高亮等) **/
                        for(var nn = 0, nlen = jmonths.length; nn < nlen; nn+=1){
                            var jmonthTop = D.offset(jmonths[nn]).top;
                            if(jmonthTop <= wTop){
                                 
                                var itemVal = D.html(jmonths[nn]),
                                // 转换02 -> 2
                                itemFChar = itemVal.substring(0,1);
                                if(itemFChar == 0){
                                    itemFChar = itemVal.substring(1,2);
                                }else{
                                    itemFChar = itemVal.substring(0,2);
                                }
                                storage(itemFChar);
                            }
                        }
                    }
                });
                // 点击控制轴任一年份时候 滚动到条目列表中相对应的年份来
               var  itemLists = D.query(_config.listContainer + " .itemList");
               S.each(itemLists,function(item,index){
                   var innerIndex;
                   E.on(item,‘click‘,function(e){
                       e.preventDefault();
                       e.halt();
                       innerIndex = index;
                       var scrollTimer,
                           DELAY = 0.3;
                       !D.hasClass(KISSY.all(this),_config.activeCls) && KISSY.all(this).addClass(_config.activeCls).siblings().removeClass(_config.activeCls);
                        
                       if(!D.hasClass(KISSY.all(this),"isClick")){
                           D.addClass(KISSY.all(this),"isClick");
                       }
                       var curThis = KISSY.all(this);
                       // 删除类
                       D.hasClass(D.get(_config.listContainer),‘isScroll‘) && D.removeClass(D.get(_config.listContainer),‘isScroll‘);
                       var headerTop = D.offset(headerTitle[index]).top;
                       scrollTimer && scrollTimer.cancel();
                       scrollTimer = S.later(function(){
                            KISSY.all("html,body").animate({"scrollTop":headerTop},DELAY,‘easeBothStrong‘,function(){
                                D.removeClass(D.query(".itemHover"),_config.highlightCls);
                                !D.hasClass(D.get(".itemHover",curThis),_config.highlightCls) && D.addClass(D.get(".itemHover",curThis),_config.highlightCls);
                                !D.hasClass(D.get(_config.listContainer),‘isScroll‘) && D.addClass(D.get(_config.listContainer),‘isScroll‘);
                            });
                        },DELAY);
                        _config.yearCallback && S.isFunction(_config.yearCallback) && _config.yearCallback();
                        self._clickMenu(itemLists,innerIndex);
                   });
                   if(innerIndex == undefined){
                      innerIndex = 0;
                      self._clickMenu(itemLists,innerIndex);
                   }
               }); 
            });
        },
        _clickMenu: function(itemLists,innerIndex) {
            var self = this,
                _config = self.config;
            if(innerIndex == undefined){
                return;
            }
            // 点击控制轴当前年份中的月份时候 滚动到当前的月份的地方。
            var itemHovers = D.query(".itemHover",KISSY.all(itemLists[innerIndex]));
            S.each(itemHovers,function(itemHover,curIndex){
                E.on(itemHover,‘click‘,function(e){
                     
                    e.halt();
                    var itemMonth = D.attr(KISSY.all(itemHover),"data-month");
                    var tempArr = [],
                        scrollTimer,
                        DELAY = 0.1;
                    console.log(itemMonth);
                    var curMonths = D.query(".left-date",D.query(".J_Year_Month")[innerIndex]);
                     // 删除类
                    D.hasClass(D.get(_config.listContainer),‘isScroll‘) && D.removeClass(D.get(_config.listContainer),‘isScroll‘);
                    KISSY.all(‘.itemHover‘).removeClass(_config.highlightCls);
                    KISSY.all(this).addClass(_config.highlightCls).siblings().removeClass(_config.highlightCls);
                    for(var i=0; i<curMonths.length; i+=1){
                        var itemVal = D.attr(curMonths[i],"videoMonth");
                        // 转换02 -> 2
                        var itemFChar = itemVal.substring(0,1);
                        if(itemFChar == 0){
                            itemFChar = itemVal.substring(1,2);
                        }else{
                            itemFChar = itemVal.substring(0,2);
                        }
                        tempArr.push(itemFChar);
                    }
                    for(var j=0; j<tempArr.length; j+=1){
                        var tempV = tempArr[j];
                        if(itemMonth == tempArr[j]){
                            var mtop = D.offset(curMonths[j]).top;
                            scrollTimer && scrollTimer.cancel();
                            scrollTimer = S.later(function(){
                                KISSY.all("html,body").animate({"scrollTop":mtop},DELAY,‘easeBothStrong‘,function(){
                                    !D.hasClass(D.get(_config.listContainer),‘isScroll‘) && D.addClass(D.get(_config.listContainer),‘isScroll‘);
                                });
                            },DELAY);
                            break; // 此break是当数组里面的月份有多个相同的时候 只取第一个月份
                        }
                    }
                    _config.monthCallback && S.isFunction(_config.monthCallback) && _config.monthCallback();
                });
            });
        }
    };
 
    return TimeLineNav;
},{requires:[‘datalazyload‘]});

 

  JS初始化如下 :
  KISSY.use("timeline/nav",function(S,obj){
       new obj().init({});
 });

转载自:http://www.cnblogs.com/tugenhua0707/

JS时间轴效果(类似于qq空间时间轴效果)