天天看點

寫代碼不用遞歸構造樹,可以嗎?看看ztree插件怎麼實作的吧

ztree是一個依靠 jQuery 庫實作的多功能 “樹插件”。其優異的性能、靈活的配置、多種功能的組合是 zTree 最大優點。這個插件我也一直在使用,真的特别的好,到現在中國各行各業好多Web系統中,都是用ztree去做樹結構導航功能。使用簡直是太容易了、太簡單了。無可挑剔!

寫代碼不用遞歸構造樹,可以嗎?看看ztree插件怎麼實作的吧

如果有了一定的程式設計能力,建議大家還是看下ztree的源碼,不管是後端還是前端,它的源碼也是值得我們參考學習的。比如本文說的樹構造的問題,部分童鞋在寫樹機構的時候,可能會用遞歸算法去把一個數組結構的資料,根據一定的辨別構造成樹機構形式(即帶有層級結構格式,例如檔案夾層級)的資料,可能在工作或生活中,受到使用的開發語言和環境的影響,沒有考慮過其他代碼邏輯是否更好的構造樹結構呢!

在某些通用的場景中,會有這種需求:我有很多種類型的數組機構的清單資料,裡面包含了層級關系的辨別,我隻要提供每種數組資料裡面辨別的名字,即可自動統一的構造成樹結構。

而ztree就是具有這種功能的一種插件。你隻要提供類似于如下的資料結構:

var nodes = [
	{id:1, pId:0, name: "父節點1"},
	{id:11, pId:1, name: "子節點1"},
	{id:12, pId:1, name: "子節點2"}
];
           

他就會自動處理,變成如下的樹結構:

var nodes = [{
   name: "父節點1", 
   id:1,
   children: [
			{id:11,name: "子節點1"},
			{id:12,name: "子節點2"}
	 ]}
];
           

那ztree是怎麼做的,首先其提供了一個【setting.data.simpleData.enable】配置項,用于告訴ztree是否是簡單格式的資料(即二維表格的資料資料),然後根據這個配置項,讓我們找到其源碼目錄下的js檔案夾下的jquery.ztree.core.js檔案,搜尋一下,大概在895行的位置上,有一段如下代碼:

if (setting.data.simpleData.enable) {
      newNodes = data.transformTozTreeFormat(setting, newNodes);
 }
           

這段代碼的意圖很明顯了吧,如果這個參數配置項為真,就把現在結構的資料傳遞到transformTozTreeFormat這個方法中,并傳回一個新結構,而這個新結構便是具有樹結構的資料了。

接下來,在搜尋一下這個方法,大概在661行左右,發現了這個方法,代碼段如下,20行左右的代碼量:

transformTozTreeFormat: function (setting, sNodes) {
    var i, l,
        key = setting.data.simpleData.idKey,
        parentKey = setting.data.simpleData.pIdKey,
        childKey = setting.data.key.children;
    if (!key || key == "" || !sNodes) return [];

    if (tools.isArray(sNodes)) {
        var r = [];
        var tmpMap = {};
        for (i = 0, l = sNodes.length; i < l; i++) {
            tmpMap[sNodes[i][key]] = sNodes[i];
        }
        for (i = 0, l = sNodes.length; i < l; i++) {
            if (tmpMap[sNodes[i][parentKey]] && sNodes[i][key] != sNodes[i][parentKey]) {
                if (!tmpMap[sNodes[i][parentKey]][childKey])
                    tmpMap[sNodes[i][parentKey]][childKey] = [];
                tmpMap[sNodes[i][parentKey]][childKey].push(sNodes[i]);
            } else {
                r.push(sNodes[i]);
            }
        }
        return r;
    } else {
        return [sNodes];
    }
}
           

讓我們來解析一下這段代碼:

1、首先讀取了3行參數配置項,動态擷取了id的名稱是那個屬性,父Id的名稱是哪個屬性,子集合是哪個屬性;

2、然後判斷是否為空資料、是否指定了id的屬性,沒有指定的話傳回目前數組;

3、定義了2個屬性:r、tmpMap,其中r用來存儲新結構資料,tmpMap用于将每一行的資料進行一個映射綁定,相當于做了一個根據唯一辨別ID快速從數組中查詢某個對象的的操作,如果要取出ID等于15的資料,直接tmpMap["15"]即可。這步驟執行完成後,我們需要知道一件事:想擷取最後那個最頂級的節點對應的資料對象,這裡是擷取不到的。

4、開始周遊資料,判斷臨時的那個tmpMap映射中是否有目前節點的父節點資料,并且目前節點的辨別和父辨別不相等:

如果條件成立,說明目前節點是那個父節點的兒子,那麼在判斷目前節點的父節點的兒子數組是否為空或者不存在,如果不存在,先初始化一個兒子的空數組,然後把目前節點,放到那個父節點的兒子數組裡面,依次循環往複,如果目前節點的父節點在臨時的tmpMap映射中不存在,說明了,這時的周遊的節點,就是是一個最頂級的節點了(有些時候根據提供的資料會是多個);

反之條件不成立,說明目前節點為頂級節點

5、傳回新的樹結構的數組。

我不知道以上我的這段解析是否可以讓你明白,建議經驗不足的開發者可以多思考一下。挺好的。

ztree這段代碼,其實非常巧妙,20行簡簡單單的代碼,不僅擴充了我們的思維方式,也提高了我們的開發能力,做某些功能開發時,也會聯想到這種思想,并用這種思想解決一些實際的構造和周遊的問題。

例如我将一個二維結構的資料,通過Map方式換成一個類似于目錄或索引的結構方式,可以快速的通過某個key去查詢到某個對象資料,然後當在某些地方需要找某個ID的時候,就不需要再次進行周遊了。

ztree的這段代碼,也利用了Javascript的方括号方式取值的文法,來擷取指定的屬性,同時這個這種文法,提高了動态性操作。

不知道這篇文章是否幫助到你了呢,如果有請點個贊,轉個發。如果有什麼想說的,可以評論,大家一起進行讨論下!

繼續閱讀