【问题标题】:Build tree from JSON array of objects从 JSON 对象数组构建树
【发布时间】:2020-06-08 21:05:12
【问题描述】:

给定以下 JSON 数组:

    [{"ID":12,"NAME":"ktc","PARENTID":0},
     {"ID":11,"NAME":"root","PARENTID":0}, 
     {"ID":1,"NAME":"rwhitney","PARENTID":0},
     {"ID":21,"NAME":"shared folder","PARENTID":0}, 
     {"ID":2,"NAME":".config","PARENTID":1}, 
     {"ID":5,"NAME":"wallpapers","PARENTID":1}, 
     {"ID":3,"NAME":"geany","PARENTID":2}, 
     {"ID":4,"NAME":"colorschemes","PARENTID":3}, 
     {"ID":13,"NAME":"efast","PARENTID":12}, 
     {"ID":15,"NAME":"includes","PARENTID":13}, 
     {"ID":14,"NAME":"views","PARENTID":13}, 
     {"ID":17,"NAME":"css","PARENTID":15}, 
     {"ID":16,"NAME":"js","PARENTID":15}]

我需要构建一个菜单树,其中包含嵌套在父文件夹下的子文件夹。

这是一些服务器端代码:

    socket.on('get-folders', function(data){
        var folders = [];
        getSession(session.key, function(currSession){
            db.rows('getFolders', currSession, [currSession.user], function(err, rows){
                if (err) {
                    socket.emit('err', 'Error is: ' + err );
                } else if(rows[0]){
                    //~ folders.push(JSON.stringify(rows));
                    socket.emit('get-folders', JSON.stringify(rows));
                    //~ n_Folders(rows, currSession, socket, folders, 0);
                }
            });
        });
    });

和客户端:

    function rtnSocket(cmd, data, cb){
        socket.emit(cmd, data);
        socket.on(cmd, cb);
    }

    rtnSocket('get-folders', folderid, function(data){
        console.log(data);
    });

有人可以帮助指导我正确的方向吗?

【问题讨论】:

  • 为此使用现有的库通常会更好。
  • 谢谢,但我需要学习树状菜单的机制。如果可以的话,我不想使用图书馆。
  • 好吧,我以为它是针对一些真正的项目的。 (我认为它会浪费很多时间)。
  • 为什么树形菜单需要服务器端?
  • 安全,它是针对一个真实项目的

标签: javascript arrays node.js json tree


【解决方案1】:

我需要在上面的 Nina 的帮助下回答我自己的问题:

使用给定的 JSON 对象 - Nina 的回答:

[{"ID":12,"NAME":"ktc","PARENTID":0},{"ID":11,"NAME":"root","PARENTID":0},{"ID":1,"NAME":"rwhitney","PARENTID":0},{"ID":21,"NAME":"shared folder","PARENTID":0},{"ID":2,"NAME":".config","PARENTID":1},{"ID":5,"NAME":"wallpapers","PARENTID":1},{"ID":3,"NAME":"geany","PARENTID":2},{"ID":4,"NAME":"colorschemes","PARENTID":3},{"ID":13,"NAME":"efast","PARENTID":12},{"ID":15,"NAME":"includes","PARENTID":13},{"ID":14,"NAME":"views","PARENTID":13},{"ID":17,"NAME":"css","PARENTID":15},{"ID":16,"NAME":"js","PARENTID":15},{"ID":27,"NAME":"images","PARENTID":16}]

我想出了这个功能:

var LHR= '',folderid = 0, parentid = 0;

    var seg = location.pathname.split('/')[2];
    if(seg){
        LHR = seg.split('_')[0];
        folderid = seg.split('_')[1] || 0;
        //~ alert(folderid);
        parentid = seg.split('_')[2] || 0;
        if(isLike(LHR,['share']) == true){
            sharedFileID = LHR.split('-')[1];
        }
    }


LHR = LHR.replace(/%20/g,' ');
var MLHR = isLike(LHR, ['share']) == true ? LHR.split('-')[0] : LHR;
var folders = '';
function recurse(data, indent, limit){
  if(limit < 10){
    for(var i = 0;i<data.length;i++){
        if(folderid == data[i].ID){
            folders += '<div><input style="margin-left:60px" type="checkbox" data-id="'+folderid+'" data-name="' + data[i].NAME + '" class="check-folder tooltip">'+
                '<img style="margin-left:0px" data-pid="'+parentid+'" id="folder-'+folderid+'" src="/fa/folder-open.svg" class="blk tooltip"> ' + MLHR.replace(/%20/g,' ') + ' </div>';
        } else {
            folders += '<input type="checkbox" style="margin-left:'+indent+'px" data-id="'+data[i].ID+'" data-name="' + data[i].NAME + '" class="check-folder tooltip">'+
                '<a style="margin-left:70px" ondrop="drop(event)" ondragover="allowDrop(event)" class="dsp-ib w150 blk folders drop drag" draggable="true" droppable="true"  href="/dashboard/'+data[i].NAME+'_'+data[i].ID+'_'+data[i].PARENTID+'">'+
                '<img data-pid="'+data[i].PARENTID+'" src="/fa/folder.svg" class="fa ml--80 blk dsp-ib" id="folder-'+data[i].ID+'"> ' + data[i].NAME + '</a><br>';
        }
      if(data[i].children){
          recurse(data[i].children, indent+=20, ++limit);
      }
    }
  }

  $('#folders').html(folders);
}

这样称呼它:

recurse(data,0,0);

该函数填充id为“文件夹”的树

输出如下:

再次感谢您让我走上正轨!

【讨论】:

    【解决方案2】:

    您可以从一个平面数据结构中收集所有节点,使用IDPARENTID 作为哈希表中的键并获取根数组作为结果。

    var data = [{ ID: 12, NAME: "ktc", PARENTID: 0 }, { ID: 11, NAME: "root", PARENTID: 0 }, { ID: 1, NAME: "rwhitney", PARENTID: 0 }, { ID: 21, NAME: "shared folder", PARENTID: 0 }, { ID: 13, NAME: "efast", PARENTID: 12 }, { ID: 2, NAME: ".config", PARENTID: 1 }, { ID: 5, NAME: "wallpapers", PARENTID: 1 }, { ID: 15, NAME: "includes", PARENTID: 13 }, { ID: 14, NAME: "views", PARENTID: 13 }, { ID: 3, NAME: "geany", PARENTID: 2 }, { ID: 17, NAME: "css", PARENTID: 15 }, { ID: 16, NAME: "js", PARENTID: 15 }, { ID: 4, NAME: "colorschemes", PARENTID: 3 }],
        tree = function (data, root) {
            var t = {};
            data.forEach(o => {
                Object.assign(t[o.ID] = t[o.ID] || {}, o);
                t[o.PARENTID] = t[o.PARENTID] || {};
                t[o.PARENTID].children = t[o.PARENTID].children || [];
                t[o.PARENTID].children.push(t[o.ID]);
            });
            return t[root].children;
        }(data, 0);
    
    console.log(tree);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

    • 我选择了单个查询,它将结果转换为可用的 JSON 对象。之前它是一组对象,看起来很笨重。
    • 这是什么意思?如有必要,请编辑问题。
    • 尼娜,我刚刚更新了我的问题以反映我现在使用的内容。我现在需要将 JSON 转换为可视层次树。你能提供什么建议吗?
    • 你可以问另一个问题,因为对于视觉外观,你需要一些风格,我需要一个例子。
    • 我试着问另一个问题,但它几乎立即关闭,所以我删除了它。看来我不擅长提问。 :(
    【解决方案3】:

    首先我们需要扁平化嵌套数组:

    const flatArray = (arr) => {
        return arr.reduce((flat, toFlatten) => {
            return flat.concat(Array.isArray(toFlatten) ? flatArray(toFlatten) : toFlatten);
        }, []);
    }
    

    然后我们可以创建一棵树:

    const makeTree = dataset => {
        let hashTable = Object.create(null)
        dataset.forEach( aData => hashTable[aData.ID] = { ...aData, childNodes : [] } )
        let dataTree = []
        dataset.forEach( aData => {
          if( aData.PARENTID ) hashTable[aData.PARENTID].childNodes.push(hashTable[aData.ID])
          else dataTree.push(hashTable[aData.ID])
        } )
        return dataTree
    }
    

    一个例子:

    let data = [
        [{ ID: 12, NAME: "ktc", PARENTID: 0 }, { ID: 11, NAME: "root", PARENTID: 0 }, { ID: 1, NAME: "rwhitney", PARENTID: 0 },
        { ID: 21, NAME: "shared folder", PARENTID: 0 }], [{ ID: 13, NAME: "efast", PARENTID: 12 }], [{ ID: 2, NAME: ".config", PARENTID: 1 },
        { ID: 5, NAME: "wallpapers", PARENTID: 1 }], [{ ID: 15, NAME: "includes", PARENTID: 13 }, { ID: 14, NAME: "views", PARENTID: 13 }],
        [{ ID: 3, NAME: "geany", PARENTID: 2 }], [{ ID: 17, NAME: "css", PARENTID: 15 }, { ID: 16, NAME: "js", PARENTID: 15 }],
        [{ ID: 4, NAME: "colorschemes", PARENTID: 3 }]];
    
    const flatArray = (arr) => {
        return arr.reduce((flat, toFlatten) => {
            return flat.concat(Array.isArray(toFlatten) ? flatArray(toFlatten) : toFlatten);
        }, []);
    }
    
    const makeTree = dataset => {
        let hashTable = Object.create(null)
        dataset.forEach( aData => hashTable[aData.ID] = { ...aData, childNodes : [] } )
        let dataTree = []
        dataset.forEach( aData => {
          if( aData.PARENTID ) hashTable[aData.PARENTID].childNodes.push(hashTable[aData.ID])
          else dataTree.push(hashTable[aData.ID])
        } )
        return dataTree
    }
    const dataTree = makeTree(flatArray(data));
    console.log(dataTree)

    【讨论】:

      【解决方案4】:

      最好将子文件夹作为子文件夹数组放在父对象中..它将消除ParentID并易于遍历

      [
        {
          "ID": 1,
          "NAME": "rwhitney",
          "PARENTID": 0,
          "SUB": [
            {
              "ID": 2,
              "NAME": ".config",
              "PARENTID": 1,
              "SUB": [
                {
                  "ID": 3,
                  "NAME": "geany",
                  "PARENTID": 2,
                  "SUB": [
                    {
                      "ID": 4,
                      "NAME": "colorschemes",
                      "PARENTID": 3
                    }
                  ]
                }
              ]
            },
            {
              "ID": 5,
              "NAME": "wallpapers",
              "PARENTID": 1
            }
          ]
        }
      ]
      

      【讨论】:

      • 问题是关于如何做到这一点。大概提供的数组结构在某处可用,现在有理由将其转换为树。
      猜你喜欢
      • 2012-12-14
      • 2019-08-20
      • 1970-01-01
      • 1970-01-01
      • 2018-03-02
      • 1970-01-01
      • 2015-05-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多