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