摘要:舉例說明如下二維數據結構總部二級門店三級門店二級門店樹狀數據結構總部二級門店三級門店二級門店但在某些插件中,或在某些特殊場景中,我們有兩種數據結構之間相互轉換的需求,需要自己寫一個輔助函數來完成。
問題背景
在一些目錄結構、機構層級等展示的場景中,我們經常會用到一些成熟的樹形插件來進行輕松展示,比如ztree等。大多數插件會支持對兩種數據源格式的解析,一種是通用的二維數據結構,一種是樹狀數據結構。對于這兩種數據結構的稱呼在各插件中可能不盡相同,這里依照二維結構和樹狀結構來稱呼。舉例說明如下:
// 二維數據結構 [{ "id": "001", "name": "總部", "parentId": "0" }, { "id": "002", "name": "二級門店1", "parentId": "001" }, { "id": "003", "name": "三級門店", "parentId": "002" }, { "id": "004", "name": "二級門店2", "parentId": "001" }] // 樹狀數據結構 [{ "id": "001", "name": "總部", "parentId": "0", "children": [{ "id": "002", "name": "二級門店1", "parentId": "001", "children": [{ "id": "003", "name": "三級門店", "parentId": "002", "children": [] }] }, { "id": "004", "name": "二級門店2", "parentId": "001", "children": [] }] }]
但在某些插件中,或在某些特殊場景中,我們有兩種數據結構之間相互轉換的需求,需要自己寫一個輔助函數來完成。這里就提供兩個這樣的工具函數來完成數據結構的轉換。
Note: 要說明的是,工具函數沒有經過大數據量轉換測試,所以對有實時性、大量源數據轉換需求的同學而言,請自行測試分析,可采取前置或異步等方案處理。由于自身技術水平的局限性,算法本身會有性能優化的空間,若有更優處理算法,還望交流分享,謝謝!
解決方案我們來分開介紹兩種數據結構之間的轉換算法,每個小結中我會先貼出整個函數的代碼清單,以便大家復制粘貼,然后會簡要說明其中大概的邏輯思路。
二維數據結構 => 樹狀數據結構/** * 將通用的二維數據結構轉換為樹狀數據結構 * @param {String} rootParentIdValue 表示根節點的父類id值 * @param {String} parentIdName 表示父類id的節點名稱 * @param {String} nodeIdName 表示二維結構中,每個對象主鍵的名稱 * @param {Array} listData 為二維結構的數據 * @return {Array} 轉換后的tree結構數據 */ function listToTree(rootParentIdValue, parentIdName, nodeIdName, listData) { if (listData instanceof Array && listData.length > 0 && listData[0][parentIdName]) { var rootList = [], nodeList = [] listData.forEach(function(node, index) { if (node[parentIdName] == rootParentIdValue) { rootList.push(node); } else { nodeList.push(node); } }); if (nodeList.length > 0 && rootList.length > 0) { childrenNodeAdd(rootList, nodeList); return rootList; } else if (rootList.length > 0) { throw new Error("沒有對應的子節點集合"); } else { throw new Error("沒有對應的父類節點集合"); } function childrenNodeAdd(rootNodeList, childrenList) { if (childrenList.length > 0) { rootNodeList.forEach(function(rootNode) { rootNode["children"] = []; var childrenNodeList = childrenList.slice(0); childrenList.forEach(function(childrenNode, childrenIndex) { if (parentIdName in childrenNode && rootNode[nodeIdName] == childrenNode[parentIdName]) { rootNode["children"].push(childrenNode); childrenNodeList.splice(childrenIndex, 1); } }); childrenNodeAdd(rootNode["children"], childrenNodeList); }); } } } else { throw new Error("格式不正確,無法轉換"); } }
此函數可通過listToTree("0", "parentId", "id", sourceData)調用測試,sourceData為文章開頭給出的二維數據結構舉例。
下面簡要介紹一下其中邏輯,第10行是簡要驗證一下入參數據的合法性,然后聲明了rootList和nodeList兩個變量。其中rootList為頂級根節點,nodeList為其他子節點集合,第14行到20行的循環便是為兩個變量賦值,之后根據兩個變量的值進一步判斷數據的合法性。在驗證之后調用childrenNodeAdd這個內部函數,此函數之后將會被遞歸調用,為每一個節點添加指定名稱為“children”的子節點數組。兩個入參分別是rootNodeList和childrenList,代表父節點集合,和其之后的所有子節點集合。在23行第一次調用時,傳入的便是頂級根節點和其之后的所有子孫節點。下面看這段帶有詳細注解的代碼片段:
function childrenNodeAdd(rootNodeList, childrenList) { if (childrenList.length > 0) { // 如果沒有子節點了就結束遞歸 //遍歷父節點集合,在子節點中查找其自身的子節點,并添加到對應的子節點數組中 rootNodeList.forEach(function(rootNode) { rootNode["children"] = []; var childrenNodeList = childrenList.slice(0); //復制一個子節點數據,用于存放剩余的子節點 //遍歷所有子節點 childrenList.forEach(function(childrenNode, childrenIndex) { if (parentIdName in childrenNode && rootNode[nodeIdName] == childrenNode[parentIdName]) { //根節點的id 等于子節點的父類id rootNode["children"].push(childrenNode); //添加對應節點歸為子節點 childrenNodeList.splice(childrenIndex, 1);//在剩余子節點中剔除已經分配過的子節點 } }); childrenNodeAdd(rootNode["children"], childrenNodeList); //剩余子節點繼續遞歸執行,每次遞歸一次就表示節點增加一級。 }); } }樹狀數據結構 => 二維數據結構
/** * 將樹狀數據結構轉換為二維數據結構 * @param {String} childrenName 樹狀結構中子節點名稱 * @param {Array} treeData 樹狀結構數據 * @return {Array} 轉換后的通用二維結構數據 */ function treeToList(childrenName, treeData) { var listData = []; transferTreeData(treeData); function transferTreeData (sourceData) { sourceData.forEach( function(node, nodeIndex) { if(node[childrenName].length > 0) transferTreeData(node[childrenName]); delete node[childrenName]; listData.push(node); }); } return listData; }
此函數可通過treeToList("children", sourceData)調用測試,sourceData為文章開頭給出的樹狀數據結構舉例。這里的邏輯比較簡單就不再贅述了。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/90515.html
摘要:關于前端框架大家都有了解,或多或少的使用過,比如,,等等。那么你是否也想自己手寫一個的前端框架呢,我們從入手,手把手教你寫基于的前端框架,在整個編寫的過程中,希望大家學習更多,理解更多。本節我們以打包工具結合轉換插件實現數據的抽象。 關于MVVM前端框架大家都有了解,或多或少的使用過,比如Angular,React,VUE等等。那么你是否也想自己手寫一個MVVM的前端框架呢,我們從Vi...
摘要:前端在開發過程中接觸到的算法最多的莫過于排序和深度優先遍歷。關于算法的遍歷過程,我簡略的畫了一個示例圖實例最近在實際業務場景中,跟后端約定頁面中所有組件的消息根據頁面上的組件聚合到一個對象中,后端返回的是類似如下的一個樹形數據結構。 showImg(https://segmentfault.com/img/remote/1460000010632752); dfs 前端在開發過程中接觸...
摘要:層疊樣式表二修訂版這是對作出的官方說明。速查表兩份表來自一份關于基礎特性,一份關于布局。核心第一篇一份來自的基礎參考指南簡寫速查表簡寫形式參考書使用層疊樣式表基礎指南,包含使用的好處介紹個方法快速寫成高質量的寫出高效的一些提示。 迄今為止,我已經收集了100多個精通CSS的資源,它們能讓你更好地掌握CSS技巧,使你的布局設計脫穎而出。 CSS3 資源 20個學習CSS3的有用資源 C...
摘要:算法的本質是對傳統遍歷算法的優化策略用三大策略將復雜度轉化為復雜度策略一中節點跨層級的移動操作特別少,可以忽略不計。當節點處于同一層級時,提供三種節點操作刪除插入移動。在舊的節點中的,它的,不滿足的條件,因此不做移動操作。 一、react diff算法 diff算法的作用 計算出Virtual DOM中真正變化的部分,并只針對該部分進行原生DOM操作,而非重新渲染整個頁面。 傳統di...
摘要:函數和所生成的過程來源譯者飛龍協議函數是計算過程的局部演化模式。在這一章中,我們會檢測一些用于簡單函數所生成過程的通用模型。也就是說,遞歸函數的執行過程可能需要再次調用這個函數。 3.2 函數和所生成的過程 來源:3.2 Functions and the Processes They Generate 譯者:飛龍 協議:CC BY-NC-SA 4.0 函數是計算過程的局部演化...
閱讀 2013·2021-09-29 09:35
閱讀 1949·2019-08-30 14:15
閱讀 2973·2019-08-30 10:56
閱讀 955·2019-08-29 16:59
閱讀 571·2019-08-29 14:04
閱讀 1302·2019-08-29 12:30
閱讀 1020·2019-08-28 18:19
閱讀 510·2019-08-26 11:51