使用嵌套的对象数组创建多级下拉列表

Posted

技术标签:

【中文标题】使用嵌套的对象数组创建多级下拉列表【英文标题】:Creating multi-level dropdown with nested array of objects 【发布时间】:2021-08-30 12:55:26 【问题描述】:

我正在尝试使用 Bootstrap 和一些 JSON 数据创建一个多级下拉菜单。

理想情况下,我希望下拉菜单具有这种嵌套功能:

我正在处理一个包含嵌套数据的对象数组,它看起来像:

[
   
    ID: 1,
    Title: "Middle Earth",
    Locations: [
        
           Category: "Lothlorien",
           Child: [
             
               PersonTitle: "Galadriel",
               Link: "https://www.galadriel.lot"
             ,
             
               PersonTitle: "Celeborn",
               Link: "https://www.celeb.lot"
             
           ]
        ,
        
           Category: "Mordor",
           Child: [
             
               PersonTitle: "Saruman",
               Link: "https://www.srmn.org"
             
           ]
        
    ]
  ,
  
    ID: 2,
    Title: "Arrakis",
    Locations: [...]
  
]

问题:

我可以使用模板文字创建子菜单功能,并从那里执行映射吗? (见下面的代码) 或者我必须为下拉菜单的每一层创建单独的$.eachforEach 块吗?例如,“为每个区域(中土、Arrakis 等)创建 1 层下拉菜单。然后为该区域内的每个位置创建一个子菜单。然后为该位置内的每个 PersonTitle 创建...”等

我以前使用过对象数组,但没有达到这种复杂程度,也没有使用数据创建子菜单下拉菜单。


这是一个代码示例:

console.log("regions", regionsData);

if (regionsData.length > 0) 
          $.each(regionsData, (index, item) => 
            const csContainer = $(".mo_cs-dropdown");

            const dropdownGroup = `
            <div class="submenu-item">
                <a class="dropdown-item dropdown-toggle dropright" data-region="$item.Title" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">$item.Title</a>
                <div class="dropdown-menu">
                    <li class="dropdown dropend">
                        <ul class="dropdown-menu aria-labelledby="dropdownMenuLink">
                            <li class="dropdown dropend">
                            $Object.keys(
                                item.Locations.map(key => 
                                    return `<a class='dropdown-item dropdown-toggle dropright' href='#' role='button' data-toggle='dropdown' aria-haspopup='true' aria-expanded='false'>$item.Locations.Child</a>`;
                                )
                            )
                            <ul class="dropdown menu" aria-labelledby="">
                                <li><a class="dropdown-item" href="#">test item</a></li>
                            </ul>
                            </li>
                        </ul>
                    </li>
                </div>
            </div>`;

            csContainer.append(dropdownGroup);
          );
 else 
...


这是console.log(regionsData) 的屏幕截图,带有编辑信息:https://i.stack.imgur.com/HQEXo.png

【问题讨论】:

您好,您使用的是哪个引导程序版本? @Swati 版本 4 【参考方案1】:

您需要遍历数组,并且在每次迭代中,您可以使用 +=html 附加到某个变量中。然后,将生成的这个 html 附加到您的 ul 标记中。

我从this 帖子中获取了一些代码,因为我们需要控制每个子菜单单击,您可以使用 jquery 代码,因此每次单击时从其他 submenu 添加/删除 show 类。

演示代码

var regionsData = [
    ID: 1,
    Title: "Middle Earth",
    Locations: [
        Category: "Lothlorien",
        Child: [
            PersonTitle: "Galadriel",
            Link: "https://www.galadriel.lot"
          ,
          
            PersonTitle: "Celeborn",
            Link: "https://www.celeb.lot"
          
        ]
      ,
      
        Category: "Mordor",
        Child: [
          PersonTitle: "Saruman",
          Link: "https://www.srmn.org"
        ]
      
    ]
  ,
  
    ID: 2,
    Title: "Arrakis",
    Locations: [
      Category: "Lothlorien1",
      Child: [
          PersonTitle: "Galadriel1",
          Link: "https://www.galadriel.lot"
        ,
        
          PersonTitle: "Celeborn",
          Link: "https://www.celeb.lot"
        
      ]
    ]
  
]
var csContainer = $(".mo_cs-dropdown");
$.each(regionsData, (index, item) => 
  //append li
  var dropdownGroup = `<li class="dropdown-submenu"><a class="dropdown-item dropdown-toggle"  id="$index_main" data-region="$item.Title" href="#"  >$item.Title</a>
                            <ul class="dropdown-menu" aria-labelledby="$index_main">`
  //loop through loaction array
  $.each(item.Locations, (index, items) => 
    dropdownGroup += ` <li class="dropdown-submenu"><a class="dropdown-toggle dropdown-item"  id="$index_inner"  href="#" >$items.Category</a><ul class="dropdown-menu" aria-labelledby="$index_inner">`
    //loop through child array
    $.each(items.Child, (index, items) => 
      dropdownGroup += ` <li><a class="dropdown-item "  href="$items.Link" aria-labelledby="$index_inner"  href="#">$items.PersonTitle</a></li>`
    )
    dropdownGroup += `</ul></li>` //closes tags
  )

  dropdownGroup += `</ul></li>`; //close tags..

  csContainer.append(dropdownGroup);
);
//on click of `a` tag
$(document).on('click', '.dropdown-menu a.dropdown-toggle', function(e) 
  if (!$(this).next().hasClass('show')) 
    $(this).parents('.dropdown-menu').first().find('.show').removeClass('show'); //remove show classs from others
  
  var $subMenu = $(this).next('.dropdown-menu');
  $subMenu.toggleClass('show');
  //on hidden...remove class as well
  $(this).parents('li.nav-item.dropdown.show').on('hidden.bs.dropdown', function(e) 
    $('.dropdown-submenu .show').removeClass('show');
  );
  return false;//prevnt deafult..
);
.dropdown-submenu 
  position: relative;


.dropdown-submenu a::after 
  transform: rotate(-90deg);
  position: absolute;
  right: 6px;
  top: .8em;


.dropdown-submenu .dropdown-menu 
  top: 0;
  left: 100%;
  margin-left: .1rem;
  margin-right: .1rem;
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">

<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>

<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <a class="navbar-brand" href="#">Navbar</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarNavDropdown">

    <ul class="navbar-nav">
      <li class="nav-item active">
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item dropdown">
        <a class="nav-link dropdown-toggle" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
          Dropdown link
        </a>
        <ul class="dropdown-menu mo_cs-dropdown" aria-labelledby="dropdownMenuLink">
        </ul>
        <li>
    </ul>
  </div>
</nav>

【讨论】:

非常感谢@swati,它运行良好。我曾考虑过为每个级别使用嵌套的$.each,但我没有正确实施它并尝试了其他一些方法来显示数据。

以上是关于使用嵌套的对象数组创建多级下拉列表的主要内容,如果未能解决你的问题,请参考以下文章

Android Retrofit 数组列表中的嵌套 JSON 对象

从嵌套列表创建数组

嵌套类对象列表的数组方法

带有对象数组的可扩展动态嵌套列表

使用python打印嵌套在数组中的json对象

当对数组适配器使用GetPosition时,具有相等字段的对象返回不相等