JS 將有父子關係的陣列轉換成樹形結構資料

eyelly發表於2018-11-26

將類似如下資料轉換成樹形的資料

[{
    id: 1,
    name: `1`,
}, {
    id: 2,
    name: `1-1`,
    parentId: 1
}, {
    id: 3,
    name: `1-1-1`,
    parentId: 2
}, {
    id: 4,
    name: `1-2`,
    parentId: 1
}, {
    id: 5,
    name: `1-2-2`,
    parentId: 4
}, {
    id: 6,
    name: `1-1-1-1`,
    parentId: 3
}, {
    id: 7,
    name: `2`,
}]

先附上程式碼

function translateDataToTree(data) {
  let parents = data.filter(value => value.parentId == `undefined` || value.parentId == null)
  let children = data.filter(value => value.parentId !== `undefined` && value.parentId != null)
  let translator = (parents, children) => {
    parents.forEach((parent) => {
      children.forEach((current, index) => {
        if (current.parentId === parent.id) {
          let temp = JSON.parse(JSON.stringify(children))
          temp.splice(index, 1)
          translator([current], temp)
          typeof parent.children !== `undefined` ? parent.children.push(current) : parent.children = [current]
        }
      }
      )
    }
    )
  }
 
  translator(parents, children)
 
  return parents
}

資料轉換後是

[
  {
    "id": 1,
    "name": "1",
    "children": [
      {
        "id": 2,
        "name": "1-1",
        "parentId": 1,
        "children": [
          {
            "id": 3,
            "name": "1-1-1",
            "parentId": 2,
            "children": [
              {
                "id": 6,
                "name": "1-1-1-1",
                "parentId": 3
              }
            ]
          }
        ]
      },
      {
        "id": 4,
        "name": "1-2",
        "parentId": 1,
        "children": [
          {
            "id": 5,
            "name": "1-2-2",
            "parentId": 4
          }
        ]
      }
    ]
  },
  {
    "id": 7,
    "name": "2"
  }
]

思路:將有父子關係的陣列資料先分為兩類,一類是沒有父節點的資料(取個別名parents),另一類是有父節點的資料(取個別名children),然後通過遍歷parents,對每一個父節點在children查詢對應的子節點,並將其放入父節點的children中(這裡我的是以children表示子節點),然後每個子節點又作為一個父節點來重複之前的動作。(可能這裡描述的不太清楚,下面我將對方法進行註釋說明)

/**
 * 該方法用於將有父子關係的陣列轉換成樹形結構的陣列
 * 接收一個具有父子關係的陣列作為引數
 * 返回一個樹形結構的陣列
 */
function translateDataToTree(data) {
  //沒有父節點的資料
  let parents = data.filter(value => value.parentId == `undefined` || value.parentId == null)
 
  //有父節點的資料
  let children = data.filter(value => value.parentId !== `undefined` && value.parentId != null)
 
  //定義轉換方法的具體實現
  let translator = (parents, children) => {
    //遍歷父節點資料
    parents.forEach((parent) => {
      //遍歷子節點資料
      children.forEach((current, index) => {
        //此時找到父節點對應的一個子節點
        if (current.parentId === parent.id) {
          //對子節點資料進行深複製,這裡只支援部分型別的資料深複製,對深複製不瞭解的童靴可以先去了解下深複製
          let temp = JSON.parse(JSON.stringify(children))
          //讓當前子節點從temp中移除,temp作為新的子節點資料,這裡是為了讓遞迴時,子節點的遍歷次數更少,如果父子關係的層級越多,越有利
          temp.splice(index, 1)
          //讓當前子節點作為唯一的父節點,去遞迴查詢其對應的子節點
          translator([current], temp)
          //把找到子節點放入父節點的children屬性中
          typeof parent.children !== `undefined` ? parent.children.push(current) : parent.children = [current]
        }
      }
      )
    }
    )
  }
 
  //呼叫轉換方法
  translator(parents, children)
 
  //返回最終的結果
  return parents
}

當然在實際開發中,可能屬性名稱的定義可能跟我例子中的不同,使用該方法的話,就需將屬性名改成實際的名稱即可,關鍵的屬性名有id,parentId,children

檢視原文

相關文章