如何使用 jQuery 将数组转换为具有展开折叠功能的树视图?

How to convert array to Tree View with expand collapse functionality using jQuery?

这有点棘手,但一些书呆子可以回答我的问题,因为我没有实现。
假设我有一个包含以下值的数组。

globalResFiltered = [];
    globalResFiltered.push({Category:"Fruit",Subcategory:"Orange",Value:"001"});
    globalResFiltered.push({Category:"Fruit",Subcategory:"Orange",Value:"012"});
    globalResFiltered.push({Category:"Fruit",Subcategory:"Orange",Value:"006"});
    globalResFiltered.push({Category:"Fruit",Subcategory:"Mango",Value:"011"});
    globalResFiltered.push({Category:"Fruit",Subcategory:"Apple",Value:"013"});
    globalResFiltered.push({Category:"Fruit",Subcategory:"Apple",Value:"004"});
    globalResFiltered.push({Category:"Fruit",Subcategory:"Apple",Value:"010"});
    
    globalResFiltered.push({Category:"Color",Subcategory:"Silver",Value:"014"});
    globalResFiltered.push({Category:"Color",Subcategory:"Silver",Value:"015"});
    globalResFiltered.push({Category:"Color",Subcategory:"Orange",Value:"005"});
    globalResFiltered.push({Category:"Color",Subcategory:"Orange",Value:"016"});
    globalResFiltered.push({Category:"Color",Subcategory:"Red",Value:"003"});
    globalResFiltered.push({Category:"Color",Subcategory:"Red",Value:"017"});
    globalResFiltered.push({Category:"Color",Subcategory:"Red",Value:"018"});
    
    globalResFiltered.push({Category:"Jewellery",Subcategory:"Bronze",Value:"019"});
    globalResFiltered.push({Category:"Jewellery",Subcategory:"Bronze",Value:"020"});
    globalResFiltered.push({Category:"Jewellery",Subcategory:"Silver",Value:"007"});
    globalResFiltered.push({Category:"Jewellery",Subcategory:"Gold",Value:"002"});
    globalResFiltered.push({Category:"Jewellery",Subcategory:"Gold",Value:"008"});
    globalResFiltered.push({Category:"Jewellery",Subcategory:"Platinum",Value:"009"});
    globalResFiltered.push({Category:"Jewellery",Subcategory:"Platinum",Value:"021"});
    
console.log(globalResFiltered);
(Please see console for array output)

完美,现在我的数组有 3 个主要类别:
水果
颜色
首饰

他们每个人都有子类别(可以重复):
水果 - 橙子、芒果和苹果
颜色 - 银色、橙色和红色
珠宝 - 青铜、白银、黄金和铂金
每个子类别都有一些值(从 001 到 021)

现在,问题的主要部分。我想将上面的数组转换为树视图。
我已经有了 HTML、JS 和 CSS 输出应该如何的代码。
这些值是硬编码的。
检查下面的片段

$(function () {
    $('.vertical-tree ul').hide();
    $('.vertical-tree>ul').show();
    $('.vertical-tree ul.active').show();
    $('.vertical-tree li').on('click', function (e) {
        var children = $(this).find('> ul');
        if (children.is(":visible")) children.hide('fast').removeClass('active');
        else children.show('fast').addClass('active');
        e.stopPropagation();
    });
});
/*-------------vertical-tree-view------------*/
.vertical-tree{
    padding-top: 40px;
    padding-bottom: 40px;
}
.vertical-tree ul{
    padding-left: 30px;
}
.vertical-tree li {
    margin: 0px 0;
    list-style-type: none;
    position: relative;
    padding: 20px 5px 0px 5px;
}
.vertical-tree li::before{
    content: '';
    position: absolute; 
    top: 0;
    width: 1px; 
    height: 100%;
    right: auto; 
    left: -20px;
    border-left: 2px solid #ccc;
    bottom: 50px;
}
.vertical-tree li::after{
    content: '';
    position: absolute; 
    top: 34px; 
    width: 25px; 
    height: 20px;
    right: auto; 
    left: -20px;
    border-top: 2px solid #ccc;
}
.vertical-tree li a{
    display: inline-block;
    padding: 8px 30px;
    text-decoration: none;
    background-color: #e1eafc;
    color: #000000;
    border: 1px solid #5285eb;
    font-size: 13px;
    border-radius: 4px;
}
.vertical-tree > ul > li::before, 
.vertical-tree > ul > li::after{
    border: 0;
}
.vertical-tree li:last-child::before{ 
        height: 34px;
}
.vertical-tree li a:hover, 
.vertical-tree li a:hover+ul li a {
    background-color: #5a8dee;
    color: #fff;
    border: 1px solid #5a8dee;
}
.vertical-tree li a:hover+ul li::after, 
.vertical-tree li a:hover+ul li::before, 
.vertical-tree li a:hover+ul::before, 
.vertical-tree li a:hover+ul ul::before{
    border-color:  #fbba00;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="mainDiv">
    <div class="vertical-tree" style="display:block;">
    <ul>
        <!--Fruit-->
        <li>
            <a href="javascript:void(0);">Fruit</a>
            <ul>
                <li>
                    <a href="javascript:void(0);">Orange</a>
                    <ul>
                        <li>
                            <a href="javascript:void(0);">001</a>
                        </li>
                        <li>
                            <a href="javascript:void(0);">012</a>
                        </li>
                        <li>
                            <a href="javascript:void(0);">016</a>
                        </li>
                    </ul>
                </li>
                <li>
                    <a href="javascript:void(0);">Mango</a>
                    <ul>
                        <li>
                            <a href="javascript:void(0);">011</a>
                        </li>
                    </ul>
                </li>
                <li>
                    <a href="javascript:void(0);">Apple</a>
                    <ul>
                        <li>
                            <a href="javascript:void(0);">013</a>
                        </li>
                        <li>
                            <a href="javascript:void(0);">004</a>
                        </li>
                        <li>
                            <a href="javascript:void(0);">010</a>
                        </li>
                    </ul>
                </li>
            </ul>
        </li>
        <!--Color-->
        <li>
            <a href="javascript:void(0);">Color</a>
            <ul>
                <li>
                    <a href="javascript:void(0);">Silver</a>
                    <ul>
                        <li>
                            <a href="javascript:void(0);">014</a>
                        </li>
                        <li>
                            <a href="javascript:void(0);">015</a>
                        </li>
                    </ul>
                </li>
                <li>
                    <a href="javascript:void(0);">Orange</a>
                    <ul>
                        <li>
                            <a href="javascript:void(0);">005</a>
                        </li>
                        <li>
                            <a href="javascript:void(0);">016</a>
                        </li>
                    </ul>
                </li>
                <li>
                    <a href="javascript:void(0);">Red</a>
                    <ul>
                        <li>
                            <a href="javascript:void(0);">003</a>
                        </li>
                        <li>
                            <a href="javascript:void(0);">017</a>
                        </li>
                        <li>
                            <a href="javascript:void(0);">018</a>
                        </li>
                    </ul>
                </li>
            </ul>
        </li>
        
        <!--Jewellery-->
        <li>
            <a href="javascript:void(0);">Jewellery</a>
            <ul>
                <li>
                    <a href="javascript:void(0);">Bronze</a>
                    <ul>
                        <li>
                            <a href="javascript:void(0);">019</a>
                        </li>
                        <li>
                            <a href="javascript:void(0);">020</a>
                        </li>
                    </ul>
                </li>
                <li>
                    <a href="javascript:void(0);">Silver</a>
                    <ul>
                        <li>
                            <a href="javascript:void(0);">007</a>
                        </li>
                    </ul>
                </li>
                <li>
                    <a href="javascript:void(0);">Gold</a>
                    <ul>
                        <li>
                            <a href="javascript:void(0);">002</a>
                        </li>
                        <li>
                            <a href="javascript:void(0);">008</a>
                        </li>
                    </ul>
                </li>
                <li>
                    <a href="javascript:void(0);">Platinum</a>
                    <ul>
                        <li>
                            <a href="javascript:void(0);">009</a>
                        </li>
                        <li>
                            <a href="javascript:void(0);">021</a>
                        </li>
                    </ul>
                </li>
            </ul>
        </li>
        
    </ul>
</div>


上面的值是硬编码的,我需要一些东西可以将数组的输出转换为上面的 HTML.
到目前为止,这是我尝试过的。它不循环子类别(不正确的输出)
另外,不确定如何显示值

var globalResFiltered = [];
    globalResFiltered.push({Category:"Fruit",Subcategory:"Orange",Value:"001"});
    globalResFiltered.push({Category:"Fruit",Subcategory:"Orange",Value:"012"});
    globalResFiltered.push({Category:"Fruit",Subcategory:"Orange",Value:"006"});
    globalResFiltered.push({Category:"Fruit",Subcategory:"Mango",Value:"011"});
    globalResFiltered.push({Category:"Fruit",Subcategory:"Apple",Value:"013"});
    globalResFiltered.push({Category:"Fruit",Subcategory:"Apple",Value:"004"});
    globalResFiltered.push({Category:"Fruit",Subcategory:"Apple",Value:"010"});
    
    globalResFiltered.push({Category:"Color",Subcategory:"Silver",Value:"014"});
    globalResFiltered.push({Category:"Color",Subcategory:"Silver",Value:"015"});
    globalResFiltered.push({Category:"Color",Subcategory:"Orange",Value:"005"});
    globalResFiltered.push({Category:"Color",Subcategory:"Orange",Value:"016"});
    globalResFiltered.push({Category:"Color",Subcategory:"Red",Value:"003"});
    globalResFiltered.push({Category:"Color",Subcategory:"Red",Value:"017"});
    globalResFiltered.push({Category:"Color",Subcategory:"Red",Value:"018"});
    
    globalResFiltered.push({Category:"Jewellery",Subcategory:"Bronze",Value:"019"});
    globalResFiltered.push({Category:"Jewellery",Subcategory:"Bronze",Value:"020"});
    globalResFiltered.push({Category:"Jewellery",Subcategory:"Silver",Value:"007"});
    globalResFiltered.push({Category:"Jewellery",Subcategory:"Gold",Value:"002"});
    globalResFiltered.push({Category:"Jewellery",Subcategory:"Gold",Value:"008"});
    globalResFiltered.push({Category:"Jewellery",Subcategory:"Platinum",Value:"009"});
    globalResFiltered.push({Category:"Jewellery",Subcategory:"Platinum",Value:"021"});
    
    var tempCat = "";
    var tempSubCat = "";
    
    $(globalResFiltered).each(function(i,v){
                    
        if(i==0 || i==1 || i==2){debugger;}
        if(tempCat != v.Category)
        {
            $("#myTree").append("<ul><li><a class='c_"+v.Category+"'>"+v.Category+"</a></li></ul>");
            $(".c_"+v.Category).after("<ul><li id='x_"+i+"_"+v.Category+"_"+v.Subcategory+"'><a>"+v.Subcategory+"</a></li></ul>");
        }
        else
        {
            $("#x_0"+v.Category+"_"+v.Subcategory).after("<li id='x_"+i+"_"+v.Category+"_"+v.Subcategory+"'><a>"+v.Subcategory+"</a></li>");
        }
        tempCat = v.Category;
                    
                    
                    
    });






$(function () {
    $('.vertical-tree ul').hide();
    $('.vertical-tree>ul').show();
    $('.vertical-tree ul.active').show();
    $('.vertical-tree li').on('click', function (e) {
        var children = $(this).find('> ul');
        if (children.is(":visible")) children.hide('fast').removeClass('active');
        else children.show('fast').addClass('active');
        e.stopPropagation();
    });
});
/*-------------vertical-tree-view------------*/
.vertical-tree{
    padding-top: 40px;
    padding-bottom: 40px;
}
.vertical-tree ul{
    padding-left: 30px;
}
.vertical-tree li {
    margin: 0px 0;
    list-style-type: none;
    position: relative;
    padding: 20px 5px 0px 5px;
}
.vertical-tree li::before{
    content: '';
    position: absolute; 
    top: 0;
    width: 1px; 
    height: 100%;
    right: auto; 
    left: -20px;
    border-left: 2px solid #ccc;
    bottom: 50px;
}
.vertical-tree li::after{
    content: '';
    position: absolute; 
    top: 34px; 
    width: 25px; 
    height: 20px;
    right: auto; 
    left: -20px;
    border-top: 2px solid #ccc;
}
.vertical-tree li a{
    display: inline-block;
    padding: 8px 30px;
    text-decoration: none;
    background-color: #e1eafc;
    color: #5a8dee;
    border: 1px solid #5285eb;
    font-size: 13px;
    border-radius: 4px;
}
.vertical-tree > ul > li::before, 
.vertical-tree > ul > li::after{
    border: 0;
}
.vertical-tree li:last-child::before{ 
        height: 34px;
}
.vertical-tree li a:hover, 
.vertical-tree li a:hover+ul li a {
    background-color: #5a8dee;
    color: #fff;
    border: 1px solid #5a8dee;
}
.vertical-tree li a:hover+ul li::after, 
.vertical-tree li a:hover+ul li::before, 
.vertical-tree li a:hover+ul::before, 
.vertical-tree li a:hover+ul ul::before{
    border-color:  #fbba00;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Incorrect, it only shows one subcategory
<div class="vertical-tree" id="myTree">
</div>

我曾尝试检查以下参考资料,但没有成功。
https://www.jqueryscript.net/table/jQuery-Plugin-For-Displaying-A-Tree-Of-Data-In-A-Table-treetable.html https://www.jqueryscript.net/demo/simple-tree-table/


在此先感谢您的帮助 '

我会分两步进行:

  • 将数据结构转换为层次结构:toHierarchy
  • 将该层次结构转换为 DOM 个元素的层次结构:createList

代码如下:

function toHierarchy(data, ...fields) {
    let map = {};
    for (let item of data) {
        let node = map;
        for (let field of fields) {
            let value = item[field];
            node = (node[value] ??= {});
        }
    }
    return map;
}

function createList(hierarchy) {
    return $("<ul>").css({display: "none"}).append(
        Object.entries(hierarchy).flatMap(([value, children]) => $("<li>").append(
             $("<a>", { href: "javascript:void(0);" }).text(value),
             createList(children)
        ))
    );
}

// Your sample data:
const globalResFiltered = [{Category:"Fruit",Subcategory:"Orange",Value:"001"},{Category:"Fruit",Subcategory:"Orange",Value:"012"},{Category:"Fruit",Subcategory:"Orange",Value:"006"},{Category:"Fruit",Subcategory:"Mango",Value:"011"},{Category:"Fruit",Subcategory:"Apple",Value:"013"},{Category:"Fruit",Subcategory:"Apple",Value:"004"},{Category:"Fruit",Subcategory:"Apple",Value:"010"},{Category:"Color",Subcategory:"Silver",Value:"014"},{Category:"Color",Subcategory:"Silver",Value:"015"},{Category:"Color",Subcategory:"Orange",Value:"005"},{Category:"Color",Subcategory:"Orange",Value:"016"},{Category:"Color",Subcategory:"Red",Value:"003"},{Category:"Color",Subcategory:"Red",Value:"017"},{Category:"Color",Subcategory:"Red",Value:"018"},{Category:"Jewellery",Subcategory:"Bronze",Value:"019"},{Category:"Jewellery",Subcategory:"Bronze",Value:"020"},{Category:"Jewellery",Subcategory:"Silver",Value:"007"},{Category:"Jewellery",Subcategory:"Gold",Value:"002"},{Category:"Jewellery",Subcategory:"Gold",Value:"008"},{Category:"Jewellery",Subcategory:"Platinum",Value:"009"},{Category:"Jewellery",Subcategory:"Platinum",Value:"021"}];   

// Convert data structure to a hierarchical one:
const hierarchy = toHierarchy(globalResFiltered, "Category", "Subcategory", "Value");

$(function () {
    // Added this line:
    $(".vertical-tree").empty().append(createList(hierarchy));
    $('.vertical-tree ul').hide();
    $('.vertical-tree>ul').show();
    $('.vertical-tree ul.active').show();
    $('.vertical-tree li').on('click', function (e) {
        var children = $(this).find('> ul');
        if (children.is(":visible")) children.hide('fast').removeClass('active');
        else children.show('fast').addClass('active');
        e.stopPropagation();
    });
});
/*-------------vertical-tree-view------------*/
.vertical-tree{
    padding-top: 40px;
    padding-bottom: 40px;
}
.vertical-tree ul{
    padding-left: 30px;
}
.vertical-tree li {
    margin: 0px 0;
    list-style-type: none;
    position: relative;
    padding: 20px 5px 0px 5px;
}
.vertical-tree li::before{
    content: '';
    position: absolute; 
    top: 0;
    width: 1px; 
    height: 100%;
    right: auto; 
    left: -20px;
    border-left: 2px solid #ccc;
    bottom: 50px;
}
.vertical-tree li::after{
    content: '';
    position: absolute; 
    top: 34px; 
    width: 25px; 
    height: 20px;
    right: auto; 
    left: -20px;
    border-top: 2px solid #ccc;
}
.vertical-tree li a{
    display: inline-block;
    padding: 8px 30px;
    text-decoration: none;
    background-color: #e1eafc;
    color: #000000;
    border: 1px solid #5285eb;
    font-size: 13px;
    border-radius: 4px;
}
.vertical-tree > ul > li::before, 
.vertical-tree > ul > li::after{
    border: 0;
}
.vertical-tree li:last-child::before{ 
        height: 34px;
}
.vertical-tree li a:hover, 
.vertical-tree li a:hover+ul li a {
    background-color: #5a8dee;
    color: #fff;
    border: 1px solid #5a8dee;
}
.vertical-tree li a:hover+ul li::after, 
.vertical-tree li a:hover+ul li::before, 
.vertical-tree li a:hover+ul::before, 
.vertical-tree li a:hover+ul ul::before{
    border-color:  #fbba00;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="mainDiv">
    <div class="vertical-tree"></div>
</div>