由於工作需要,要直觀的看到某個業務是由那些子業務引起的異常,所以我需要用樹表的方式來展現各個層次的數據。
需求:
1、數據層次分明;
2、數據讀取慢、需要動態加載孩子節點;
3、支持默認展開多少層。
在網上找到了很多資料,發現treeTable方面的組件質量都不高,有些還不錯樣式不符合,性能也比較差。想想樹表也挺簡單的,不就是通過隱藏或者展現某些tr來實現嘛。於是乎,自己寫一個。
2011年5月4號恰好放假一個下午,於是在家里風風火火開始構造自己的樹表插件。
樣式我就用了http://www.hanpau.com/index.php?page=jqtreetable,包括圖片以及參數命名都借鑒了。但這款插件質量不怎樣,使用方式很麻煩,效率低。
一、使用接口
個人覺得,接口這部分是一款插件是否好用的核心。
jqTreeTable的用法:
html結構
- <span style="font-size: small;"><table id="id">
- <tr><td>1</td></tr>
- <tr><td>2</td></tr>
- <tr><td>3</td></tr>
- <tr><td>4</td></tr>
- </table></span>
js調用
- <span style="font-size: small;">var map = [0, 1, 1, 0, 4, 5];
- var options = {};
- $("#id").jqTreeTable(map, options);</span>
這個使用方式比較麻煩,后台不僅要構造html,而且還要構造出map的數組。
所以,我自己的組件改造了這種結構,如下:
html結構
- <span style="font-size: small;"><table id="id">
- <tr id="1"><td>1</td></tr>
- <tr id="2" pId="1"><td>2</td></tr>
- <tr id="3" pId="1"><td>3</td></tr>
- <tr id="4" pId="3"><td>4</td></tr>
- </table></span>
js調用
- <span style="font-size: small;">var options = {};
- $("#id").jqTreeTable(options);</span>
我這種方式只需要構造html,把父子關系當作自定義屬性放在html中,使用相對方便。(注意:我剛開始是使用 key="1" pKey="2"的方式來標識一行的數據,以及行之間的關系,但想到以后通過自定義屬性key來選擇行效率比較低,所以改為id來存儲行的唯一標識。)
二、html的格式
在jqTreeTable中:
扣紅的html對應的格式是:
- <span style="font-size: small;"><tr>
- <td>6</td>
- <td>
- <img src="../images/vertline.gif" class="preimg">
- <img src="../images/vertline.gif" class="preimg">
- <img src="../images/blank.gif" class="preimg">
- <img src="../images/tv-collapsable.gif" class="parimg" id="treet16">Child of 4
- </td>
- <td>[0, 2, 3, 4, 6] </td>
- <td>4</td>
- <td>[7]</td>
- </tr></span>
這里有兩個問題:
1、都用圖片在網速慢的情況時會產生很多圖片占用符...,不好看。
2、直接用圖片會產生很多小圖片,且不能合並。
以下是我優化的結構:
- <span style="font-size: small;"><tr>
- <td>6</td>
- <td>
- <span class="pre_span">
- <span class="vertline"></span>
- <span class="vertline"></span>
- <span class="blank"></span>
- </span>
- <span class="collapsable"></span>
- Child of 4
- </td>
- <td>[0, 2, 3, 4, 6] </td>
- <td>4</td>
- <td>[7]</td>
- </tr></span>
這樣解決了上述問題:
1、在網速慢的情況時只不過看不到背景,可不會出現圖片占用符。
2、使用背景偏移的方式,可以把小圖片合並在同張圖片中。
三、原創treeTable的實現
基本邏輯
1、展開節點的圖標有分最后一個跟非最后一個,例如:展開節點時最后一個的展開和最后一個的展開
。(需要isLastOne)
2、如果父節點是最后一個節點,則前綴加,如果父節點不是最后一個節點,則前綴加
。(需要isLastOne、hasChild)
3、如果有孩子,則顯示+或-號,如果沒有則是普通的葉子節點。(需要hasChild)
實現過程
1、在html中,我只是把父子節點的關系寫在自定義屬性,但對於節點是否有孩 子(hasChild),是否是最后一個節點(isLastOne),是否是第一個節點(isFirstOne),都還不知道。所以第一步要分析出這些信 息,把這些信息都記錄到自定義屬性。【注意:這些信息其實也可以記錄到DOM對象的自定義屬性中,但DOM對象的自定義屬性無法在生成html的時候初始 化,所以不采用。】
2、先掃描所有的tr,構造出兩個map,分別記錄{'pId' => ['id1', 'id2']}和{id => pId}的關系。
3、再次掃描所有的tr,根據兩個map的關系,給tr增加hasChild、isLastOne、isFirstOne等自定義標簽,並開始構造節點圖標。
4、給整個table增加點擊事件監控,如果是來自(hasChild)的父節點則進行點擊事件。【亮點:jqTreeTable是給每個圖標都綁定事件,而我是給整個table綁定一個點擊事件,提高性能。】
最后效果:
5月4號那天,花了下午完成基本功能,晚上一直自主加班到1點完善功能和優化性能,包括使用span替換img,使用table整體的點擊事件等。為自己的執着而加班,最后效果還比較滿意。還差將圖片合並成一張,再改改css,就ok了。
原創jquery插件treeTable v1.1
這個版本提高了性能,做了以下改進:
* 1、使用了Css Sprite Tools 合並了分散的圖標
* 2、使用了.id的方式來代替原來[pId=id],這樣選擇孩子效率更高
* 3、把css剝離出來,增加動態添加css,每次家在前判斷是否添加過
關於第二點,非常感謝onli同學的提醒。但我並沒有直接修改我的接口,直接除去pId,而是在第一次遍歷時將pId作為class名添加到節點中。這樣有兩個好處:
(1)接口可讀性會比較好,pId比class更容易理解。
(2)第二點,如果直接使用class,那節點本來就有樣式,這樣獲取到的className還要去分解空格得到pId,挺麻煩的。
* 1、增加onSelect事件,onSelect: function($treeTable, id){}
* 2、增加beforeExpand事件,beforeExpand : function($treeTable, id){}
動態加載節點就靠beforeExpand 事件了。
* 1、修復了多個tableTree不在同個頁面的bug,並且可以讓不同的tableTree使用不同的主題。
* 2、增加了controller的自定義標簽來控制可點擊的區域。