時間軸1

前言

FineUI控件庫發展至今已經有 5 個年頭,目前論壇註冊的QQ會員 5000 多人,捐贈用戶 500 多人(捐贈用戶轉化率達到10%以上,在國內開源領域相信這是一個夢幻數字!也足以證實FineUI旺盛的生命力!)。這一切的得來不是平白無故的,而是來自於FineUI的發佈理念 – Release Early! Release Often!javascript

時至今天,FineUI總共發佈了 100 多個版本html

這 100 多個版本更新列表只是文本文件就有 120K 大小,放在頁面上更是長的要命,如何恰當的向用戶展現 FineUI 勤勞的身影就成了一個問題。以前的展現頁面只是簡單的將全部的更新記錄放在一個 PRE 標籤中,顯得有點死氣沉沉,以下圖所示。java

image

 

站在巨人的肩膀上

因爲前段時間時間軸形式的展現方式比較火,就考慮採用這種方式。可是查閱了網上的jQuery timeline plugin,大部分都比較臃腫,還須要建立Google Spreadsheet Template,而且經過JavaScript調整時間軸中每一個記錄的位置,也不適合軟件更新記錄這樣大數據集的展示。ajax

其實我須要的只是一個簡單、漂亮的數據展現方式,很快我找到了這個例子:http://tympanus.net/Blueprints/VerticalTimeline/正則表達式

image

這個界面風格給人眼前一亮的感受。在快速瀏覽以後,我發現這裏面用到了內嵌字體和CSS3的諸多知識來生成哪些漂亮的圖片,因此在IE七、IE8下瀏覽會亂做一團,以下圖所示:app

image

 

不要緊,咱們就用簡單的圖片來代替,其實我最想要的就是左側的那個垂直直線和那個圓粑粑,網頁截圖,而後用PhotoShop作簡單的處理,獲得以下三張圖片。ide

1. 垂直線(10*7)工具

version_line

2. 淺色的圓粑粑(56*56)開發工具

version_dot_alt

3. 深色的圓粑粑(56*56)字體

version_dot

兩個不一樣顏色的圓粑粑是爲了讓列表看起來更靈動一點。

 

俺的PhotoShop功底不咋地,你會發現那兩個圓粑粑不是透明背景,而是白色背景的,不要緊,只要咱們使用精確的CSS定位,看不出破綻的,^_^

 

最終咱們但願實現的效果以下圖所示。

image

其中圓粑粑中的數字表示軟件的第幾個版本,是否是看着比原來的好多了。

 

下面咱們就動手實現,純手工哦,用到的開發工具只有Notepad++(My favorite!)。

 

最簡單的HTML結構

HTML結構必定要保持簡單,其實就是一個列表嘛,那就用 UL 標籤實現。

   1:  <ul class="timeline">
   2:      <li>
   3:          <div class="time">時間</div>
   4:          <div class="version">版本號</div>
   5:          <div class="number">第幾個版本</div>
   6:          <div class="content">
   7:              <pre>
   8:                  更新記錄
   9:              </pre>
  10:          </div>
  11:      </li>
  12:  <ul>

 

初步的設想是content左邊留白,time/version/number所有浮動起來,這樣方便定位。

特別是number的定位要準確,不然圓粑粑和背景垂直線就重合不到一塊兒了。這就要看CSS的了。

 

最簡單的CSS

咱們主要來看看如何對number的定位,完整的代碼在文章最後會給出。

   1:  ul.timeline {
   2:      list-style-type: none;
   3:      background: url("../res/img/version_line.png") repeat-y scroll 120px 0 transparent;
   4:      margin: 50px 0;
   5:      padding: 0;
   6:  }
   7:  ul.timeline li {
   8:      position: relative;
   9:      margin-bottom: 20px;
  10:  }
  11:   
  12:  ul.timeline li .number {
  13:      position: absolute;
  14:      background: url("../res/img/version_dot.png") no-repeat scroll 0 0 transparent;
  15:      width: 56px;
  16:      height: 56px;
  17:      left: 97px;
  18:      line-height: 56px;
  19:      text-align: center;
  20:      color: #fff;
  21:      font-size: 18px;
  22:  }

 

首先,將垂直藍色的背景線放在最外層的 UL 標籤上,距離左側 120px;

其次,設置 LI 爲相對定位,爲 LI 中元素的絕對定位作鋪墊;

最後,將number浮動起來,主要是number的left屬性必定要精確!

 

如何計算 number 的 left 屬性那,你們看看以下的公式是否合你口味:

number.left = line.left + line.width/2 – number.width/2

                      = 120 + 10/2 – 56/2

                      =  97

 

最簡單的JQUERY

剩下就是jQuery的任務了,咱們須要使用jQuery完成以下兩點任務:

1. 動態計算 number 的數字;

2. 爲間隔行的 LI 節點添加 alt 類。

   1:  $(function() {
   2:              
   3:      var liNodes = $('ul.timeline li'), count = liNodes.length, i, liNode;
   4:      for(i=0; i<count; i++) {
   5:          liNode = $(liNodes.get(i));
   6:          if(i % 2 !== 0) {
   7:              liNode.addClass('alt');
   8:          }
   9:          liNode.find('.number').text(count - i);
  10:      }
  11:   
  12:  });

 

 

最簡單的數據遷移(正則表達式替換)

還有一項重要的任務,如何把 100 多條數據遷移到新的 HTML 結構中去,沒人願意手工去作,不要緊咱們有好幫手 Notepad++。

image

查找目標:\+(\d{4}-\d{2}-\d{2})\s+(v\d+.*)$

替換爲:</pre></div></li>\r\n<li><div class="time">$1</div><div class="version">$2</div><div class="number"></div><div class="content"><pre>

 

查找目標用來匹配相似「+2013-07-29 v3.3.1」的字符串,一次搞定,是否是很舒服。

 

完成效果

image

列表實在是太長,這裏只是 5% 不到的截圖!

 

優化!將頁面大小由150K減小爲20K

原本文章就此結束了,但是吃完飯我就不滿意了,還有改進的餘地!

1. 一次展現 100 多個記錄,用戶也看不完,反而影響顯示效果,長長長長長長長長長的滾動條;

2. 用戶關心的可能只是最近的幾回更新記錄,若是須要看更多的,提供一種方法便可!

 

基於以上考慮,咱們能夠將 100 多個記錄分紅 20 個記錄一個文本文件保存起來,須要的時候經過 AJAX 獲取就好了。

頁面首次加載只須要前 10 條左右的記錄便可,在列表的最後添加一個大大的按鈕,以下圖所示。

image

 

最終的目錄結構以下所示。

image

 

來體驗一下最終的效果吧:

http://fineui.com/version

 

 

所有源代碼

   1:  <style>
   2:      ul.timeline {
   3:          list-style-type: none;
   4:          background: url("../res/img/version_line.png") repeat-y scroll 120px 0 transparent;
   5:          margin: 50px 0;
   6:          padding: 0;
   7:      }
   8:   
   9:      ul.timeline li {
  10:          position: relative;
  11:          margin-bottom: 20px;
  12:      }
  13:      ul.timeline li .time {
  14:          position: absolute;
  15:          width: 90px;
  16:          text-align: right;
  17:          left: 0;
  18:          top: 10px;
  19:          color: #999;
  20:      }
  21:      ul.timeline li .version {
  22:          position: absolute;
  23:          width: 290px;
  24:          text-align: right;
  25:          left: -200px;
  26:          top: 30px;
  27:          font-size: 40px;
  28:          line-height: 50px;
  29:          color: #3594cb;
  30:          overflow: hidden;
  31:      }
  32:      ul.timeline li .number {
  33:          position: absolute;
  34:          background: url("../res/img/version_dot.png") no-repeat scroll 0 0 transparent;
  35:          width: 56px;
  36:          height: 56px;
  37:          left: 97px;
  38:          line-height: 56px;
  39:          text-align: center;
  40:          color: #fff;
  41:          font-size: 18px;
  42:      }
  43:      ul.timeline li.alt .number {
  44:          background-image: url("../res/img/version_dot_alt.png");
  45:      }
  46:      ul.timeline li .content {
  47:          margin-left: 180px;
  48:          
  49:      }
  50:      ul.timeline li .content pre {
  51:          background-color: #3594cb;
  52:          padding: 20px;
  53:          color: #fff;
  54:          font-size: 13px;
  55:          line-height: 20px;
  56:      }
  57:      ul.timeline li.alt .content pre {
  58:          background-color: #43B1F1;
  59:      }
  60:  </style>
  61:  <ul class="timeline">
  62:      <li>
  63:          <div class="time">2013-07-29</div>
  64:          <div class="version">v3.3.1</div>
  65:          <div class="number"></div>
  66:          <div class="content">
  67:              <pre>
  68:              -將工具YUICompressor替換爲Microsoft Ajax Minifier(須要指定-evals:immediate)。
  69:              ...        
  70:              </pre>
  71:          </div>
  72:      </li>
  73:      ...
  74:  </ul>
  75:  <script>
  76:      $(function() {
  77:      
  78:          var nextDataNumber = 5;
  79:          
  80:          var ulNode = $('ul.timeline');
  81:          
  82:          function initLiNodes() {
  83:              var liNodes = ulNode.find('li'), count = liNodes.length, i, liNode, leftCount = nextDataNumber * 20;
  84:              for(i=0; i<count; i++) {
  85:                  liNode = $(liNodes.get(i));
  86:                  if(i % 2 !== 0) {
  87:                      liNode.addClass('alt');
  88:                  } else {
  89:                      liNode.removeClass('alt');
  90:                  }
  91:                  liNode.find('.number').text(leftCount + count - i);
  92:              }
  93:          }
  94:          
  95:          
  96:          $('#fetchNextData').click(function() {
  97:              var $this = $(this);
  98:              $this.addClass('disabled').text('......');
  99:              
 100:              $.get('./version_data_' + nextDataNumber +'.txt', function(data) {
 101:                  ulNode.append(data);
 102:                  $this.removeClass('disabled').text('後二十條數據');
 103:                  nextDataNumber--;
 104:                  
 105:                  if(nextDataNumber === 0) {
 106:                      $this.hide();
 107:                  }
 108:                  
 109:                  initLiNodes();
 110:              });
 111:              
 112:          });
 113:      
 114:          initLiNodes();
 115:          
 116:      });
 117:  </script>

 

小結

如何向用戶有效的展現 100 多條更新記錄,是個技術活。須要咱們認真思考,學以至用,用最簡單的HTML、CSS、JQUERY來實現最好的用戶體驗。

 

後記 

開源中國的網友 混世頑童 提到是否能夠在滾動條到達底部時自動加載後20條數據,這個也很容易實現,更新後的JavaScript代碼以下所示。

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
$( function () {
         
     var  nextDataNumber = 5;
     var  ajaxLoading =  false ;
     var  docNode = $(document);
     
     var  ulNode = $( 'ul.timeline' );
     
     function  initLiNodes() {
         var  liNodes = ulNode.find( 'li' ), count = liNodes.length, i, liNode, leftCount = nextDataNumber * 20;
         for (i=0; i<count; i++) {
             liNode = $(liNodes.get(i));
             if (i % 2 !== 0) {
                 liNode.addClass( 'alt' );
             else  {
                 liNode.removeClass( 'alt' );
             }
             liNode.find( '.number' ).text(leftCount + count - i);
         }
     }
     
     
     $( '#fetchNextData' ).click( function () {
         var  $ this  = $( this );
         $ this .addClass( 'disabled' ).text( '正在加載後二十條數據...' );
         ajaxLoading =  true ;
         
         $.get( './version_data_'  + nextDataNumber + '.txt' function (data) {
             ajaxLoading =  false ;
             ulNode.append(data);
             $ this .removeClass( 'disabled' ).text( '後二十條數據' );
             nextDataNumber--;
             
             if (nextDataNumber === 0) {
                 $ this .hide();
             }
             
             initLiNodes();
         });
         
     });
 
     initLiNodes();
     
     docNode.scroll( function () {
         
         if (docNode.height() - $(window).height() - docNode.scrollTop() < 10) {
             if (!ajaxLoading) {
                 $( '#fetchNextData' ).click();
             }  
         }
         
     });
     
});