【问题标题】:How do I create a drop down menu without nested lists?如何创建没有嵌套列表的下拉菜单?
【发布时间】:2014-12-18 21:53:33
【问题描述】:

我正在尝试实现一个基本的 CSS 下拉菜单,其中没有列表中的嵌套列表。换句话说正常的方式是:

<ul>
    <li><a>Blah</a></li>
    <li><a>Blah Parent</a>
        <ul>
            <li><a>Blah Child</a></li>
        </ul>
    </li>
</ul>

我需要这样做的方式是:

<ul>
    <li><a>Blah</a></li>
    <li><a>Blah Parent</a></li>
    <li class="childitem"><a>Blah Parent</a><li>
    <li class="childitem"><a>Blah Parent</a><li>
    <li><a>Blah</a></li>
    <li><a>Blah</a></li>
    <li class="childitem"><a>Blah Parent</a><li>
    <li class="childitem"><a>Blah Parent</a><li>
</ul>

有没有办法用纯 CSS 来做到这一点?还是借助一些基本的 js 帮助?

【问题讨论】:

  • 问题在于使用这种不明确的编码结构将子项与父项相关联。
  • 这只是其中一个问题,可以通过.childitem 上的data-parent="%parent_id%" 和顶级项目上的id 来解决。更大的问题是为什么你会想要这样做。它破坏了您的 HTML 中的语义,并将孩子与父母分离,除了您需要在渲染后的元素上执行的一些体操。使这变得不必要的复杂的最重要的需求是什么?
  • 另一个大问题是使用 JS 来解决这将是“真正的”主要方式来做到这一点。 WHich 是不可靠的,因为不是每个用户都允许 JS,所以他们会看到一个损坏的列表。 CSS 是更常见的方式,因为您永远不会真正关闭它。除非你是一个开发者并且已经崩溃了。
  • 当然可以通过一些 DOM 操作来完成,但是您的结构将不直观且难以理解。你为什么要尝试做一件简单的事情却困难重重?嵌套列表有什么问题?
  • 为什么要重新发明轮子?是什么因素让你说你必须这样做?

标签: javascript jquery css drop-down-menu html-lists


【解决方案1】:

您想要的结果实际上有点模棱两可,但有几种方法可以解决这个问题。

解决方案 1 - 更改 DOM

如果你想动态改变 DOM,你可以使用 jQuery 的 nextUntil() 来找到要移动的兄弟元素:

JSFiddle: http://jsfiddle.net/TrueBlueAussie/9afavum5/

// Solution 1 - change the DOM
$("ul li:not(.childitem)").each(function () {
    var children = $(this).nextUntil(":not(.childitem)");
    if (children.length) {
        $(this).append($("<ul>").append(children));
    }
});

这可以通过找到预期的父元素(:not 有 .childitem),然后使用 nextUntil 找到兄弟元素直到下一个父元素。

解决方案 2 - 切换现有

如果您只是想切换到子项,而不是更改 DOM,您可以使用类似的匹配技术来查找兄弟项:

JSFiddle: http://jsfiddle.net/TrueBlueAussie/9afavum5/1/

// Solution 2 - toggle the siblings
$("ul li.childitem").hide();
$("ul li:not(.childitem)").click(function(){
    $(this).nextUntil(":not(.childitem)").toggle();
});

【讨论】:

    【解决方案2】:

    确实,“借助一些基本的 js 帮助”,您只需要一个简单的“单线”(在您的函数中)来修复 HTML,这里是 格式化 以提高可读性(以及在 cmets 中的解释):

    function nestSubULbyClass(par, cls){
      for( var elms=par.getElementsByTagName('li'), L=elms.length, t
         ; L-- //loop through elements in reverse to avoid nested look-ahead loop(s)
         ; ~(' '+elms[L].className+' ').indexOf(cls)  //if   current elm contains specified class
           ? (t || (t=document.createElement('ul'))   //then take temp UL or create a new one
             ).appendChild(par.removeChild(elms[L]))  //     and move current elm to temp UL
           : t && (elms[L].appendChild(t), t=0)       //else append temp UL to current elm 
         );                                           //     and clear temp with falsy value
    }
    
    //"Make it so, number one!!"  Note this is just an example, hook and pass UL any way you like
    window.onload=function(){
      nestSubULbyClass(document.getElementsByTagName('ul')[0], 'childitem');
    };
    <ul>
        <li><a>Blah</a></li>
        <li><a>Blah Parent</a></li>
        <li class="childitem"><a>Blah Parent</a></li>
        <li class="childitem"><a>Blah Parent</a></li>
        <li><a>Blah</a></li>
        <li><a>Blah</a></li>
        <li class="childitem"><a>Blah Parent</a></li>
        <li class="childitem"><a>Blah Parent</a></li>
    </ul>

    编辑:
    从这里开始,现在可以简单地使用任何基于纯 CSS 的下拉菜单(和样式),而不需要任何其他 javascript 处理程序(很好)!

    对于以下示例,我使用了来自this answer 的css。注意:我从单行 中删除了 cmets 和格式(幽默任何认为非上下文感知标准格式更好阅读的人 ☺)

    function nestSubULbyClass(par, cls) {
      for(var elms=par.getElementsByTagName('li'), L=elms.length, t; L--; ~(' '+elms[L].className+' ').indexOf(cls) ? (t || (t=document.createElement('ul'))).appendChild(par.removeChild(elms[L])) : t && (elms[L].appendChild(t), t=0));
    }
    
    window.onload=function(){
      nestSubULbyClass(document.getElementsByTagName('ul')[0], 'childitem');
    };
    ul {
        font-family: Arial, Verdana;
        font-size: 14px;
        margin: 0;
        padding: 0;
        list-style: none;
    }
    
    ul li {
        display: block;
        position: relative;
        float: left;
    }
    
    li ul {
        display: none;
    }
    
    ul li a {
        display: block;
        text-decoration: none;
        color: #ffffff;
        border-top: 1px solid #ffffff;
        padding: 5px 15px 5px 15px;
        background: #2C5463;
        margin-left: 1px;
        white-space: nowrap;
    }
    
    ul li a:hover {
        background: #617F8A;
    }
    
    li:hover ul {
        display: block;
        position: absolute;
    }
    
    li:hover li {
        float: none;
        font-size: 11px;
    }
    
    li:hover a {
        background: #617F8A;
    }
    
    li:hover li a:hover {
        background: #95A9B1;
    }
    <ul>
        <li><a>Blah</a></li>
        <li><a>Blah Parent</a></li>
        <li class="childitem"><a>Blah Parent</a></li>
        <li class="childitem"><a>Blah Parent</a></li>
        <li><a>Blah</a></li>
        <li><a>Blah</a></li>
        <li class="childitem"><a>Blah Parent</a></li>
        <li class="childitem"><a>Blah Parent</a></li>
    </ul>

    【讨论】:

    • 你用什么来格式化那个代码?这是我最近看到的可读性最低的 javascript,但你特别说“这里它的格式是为了更好的可读性”所以虽然我应该问:)
    • @TrueBlueAussie:我使用记事本(一如既往)和我的大脑。 不更改代码(由于水平长度,仅在一行上格式化时很难阅读),您将如何格式化它? my 的眼睛所见:啊,一个只包含一个无体 for 循环的实用程序函数。三个 for 部分 ; 清楚地排列在 for 的 () 之间。第 1 行启动必要的局部变量,第 2 行是循环条件,使两行都清楚地循环通过传递的容器的元素。剩下的就是第三行,包含三元组。
    • 三元显然做了布尔测试(不知情的人应该想知道..哪一行以?开头)。同样:。如果有人仍然错过了这是一个三元组(与 for 循环的模式相同),他们应该刷新他们的 ES!所以让我们读一下这个三元组:显然它声明:“如果当前元素属于类'childitem',那么(?)我们采用我们的 temp 列表容器元素或创建一个新的并移动我们的当前元素到那个容器元素。ELSE : 如果我们有一个容器元素,我们将它附加到当前元素并清除 t(我使用 0,因为它是最短的)。防水循环。
    • 可能更有趣的是为什么循环会反向。那是因为否则需要一个额外的“前瞻”循环。然而反过来,我们应该总是找到一个(预期的)父元素(如果交付的 html 代码保持这种常规格式)。结合简单的 appendChild,我们可以免费获得分组子元素的正确顺序。我们现在也不需要在循环条件中进行比较只是另一个免费的奖励。换句话说:“工作”不是为反向循环量身定制的,相反,最简单的“工作”(折叠起来)需要反向循环
    • 我想结束:我将实用功能程序流程区分开来。我认为这个函数在(更具描述性的)程序流代码中是一个实用函数used(但是你可能不应该将它命名为“demo”,但我会将命名问题/约定留给使用效用函数的人)。同样,大多数人从不阅读他们包含的库(尤其是如果他们使用自动最新和最棒的链接)。
    【解决方案3】:

    只要有身份证和班级FIDDLE HERE就可以了

    这里

    <ul>
        <li><a>Blah</a></li>
        <li class="drp"><a>Blah Parent</a></li>
        <li class="childitem"><a>Blah Parent</a><li>
        <li class="childitem"><a>Blah Parent</a><li>
    </ul>
    

    JS

    $(document).ready(function(){
      $(".drp").hover(function(){
           $(".childitem").slideToggle("fast");
        },function(){
             $(".childitem").hide();
      });
      $(".childitem").hover(function(){
           $(".childitem").show();
        },function(){
             $(".childitem").hide();
      });
    });
    

    CSS

    .drp:hover
    {
        cursor: pointer;   
    }
    ul li
    {
        list-style-type: none;
    }
    .childitem
    {
        display: none;
    }
    .childitem:hover
    {
        background: green;
        cursor: pointer;
    }
    

    【讨论】:

      【解决方案4】:
      Here is an example which uses CSS and a javascript.
      
      <div class="topnav" id="myTopnav">
        <a href="home.html" class="active">Home</a>
      
        <div class="dropdown">
          <button class="dropbtn">Products
            <i class="fa fa-caret-down"></i>
          </button>
          <div class="dropdown-content">
            <a href="plinkone.html">Link 1</a>
            <a href="#">Link 2</a>
            <a href="#">Link 3</a>
          </div>
        </div>
      
        <div class="dropdown">
          <button class="dropbtn">Services
            <i class="fa fa-caret-down"></i>
          </button>
          <div class="dropdown-content">
            <a href="slinkone.html">Link 1</a>
            <a href="#">Link 2</a>
            <a href="#">Link 3</a>
          </div>
        </div>
      
       <a href="a.html">About</a>
        <a href="news.html">News</a>
        <a href="c.html">Contact</a>
        <a href="javascript:void(0);" style="font-size:15px;" class="icon" onclick="myFunction()">&#9776;</a>
      </div>
      
      Here is the javascript:
      
      <script>
      function myFunction() {
          var x = document.getElementById("myTopnav");
      
          if (!x.classList.contains("responsive")) {
              x.classList.add("responsive");
          } else {
      
              x.classList.remove("responsive");
          }
      }
      </script>
      
      and the CSS
      
      .topnav {
        background-color: #333;
        overflow: ;
      
      }
      
      .topnav::after {
          clear: both;
          content: "";
          display: block;
      }
      
      .topnav a {
        float: left;
        display: block;
        color: #f2f2f2;
        text-align: center;
        padding: 14px 16px;
        text-decoration: none;
        font-size: 17px;
      }
      
      .active {
        background-color: ;
        color: white;
      }
      
      .topnav .icon {
        display: none;
      }
      
      .dropdown {
          float: left;
          overflow: ;
      }
      
      .dropdown .dropbtn {
          font-size: 17px;   
          border: none;
          outline: none;
          color: white;
          padding: 14px 16px;
          background-color: #333;
          font-family: inherit;
          margin: 0;
      }
      
      .dropdown-content {
          display: none;
          position: absolute;
          background-color: #f9f9f9;
          min-width: 160px;
          box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
          z-index: 1;
      }
      
      .dropdown-content a {
          float: none;
          color: black;
          padding: 12px 16px;
          text-decoration: none;
          display: block;
          text-align: left;
      }
      
      .topnav a:hover, .dropdown:hover .dropbtn {
        background-color: #555;
        color: white;
      }
      
      .dropdown-content a:hover {
          background-color: #ddd;
          color: black;
      }
      
      .dropdown:hover .dropdown-content {
          display: block;
      }
      
      @media screen and (max-width: 600px) {
        .topnav a:not(:first-child), .dropdown .dropbtn {
          display: none;
        }
        .topnav a.icon {
          float: right;
          display: block;
        }
      }
      
      @media screen and (max-width: 600px) {
        .topnav.responsive {position: relative;}
        .topnav.responsive .icon {
          position: absolute;
          right: 0;
          top: 0;
        }
        .topnav.responsive a {
          float: none;
          display: block;
          text-align: left;
        }
        .topnav.responsive .dropdown {float: none;}
        .topnav.responsive .dropdown-content {position: relative;}
        .topnav.responsive .dropdown .dropbtn {
          display: block;
          width: 100%;
          text-align: left;
        }
      }
      

      【讨论】:

      • 那是一大段代码!对于未来的读者来说,一些解释会很好也很容易剖析
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-28
      • 1970-01-01
      • 1970-01-01
      • 2017-03-06
      • 2020-05-01
      • 1970-01-01
      相关资源
      最近更新 更多