【问题标题】:sidebar multi level animated dropdown menu in vanilla jsvanilla js中的侧边栏多级动画下拉菜单
【发布时间】:2020-12-30 04:55:36
【问题描述】:

赏金

我在谷歌上搜索它以找到类似的库,但我没有找到......如果有人知道你可以给出答案(只有 vanilla js 库和 MIT 许可证)......

否则不要更改html结构...修复我的代码对我来说会更好..否则您可以自己解决..

结束赏金

const dataKeys = document.querySelectorAll('nav ul')
dataKeys.forEach(function(el,key){
    el.setAttribute('data-key',key);
})


const lists = document.querySelectorAll('ul ul')
lists.forEach(function(el){
    let sh = el.scrollHeight;
    el.setAttribute('data-sh',sh);
    el.classList.add('sub-menu')
    el.style.maxHeight =  0 + "px"; 
})
document.querySelectorAll("ul li").forEach(el => el.addEventListener('click', function(e){
    e.preventDefault();
    e.stopPropagation();
    try {
      let el = e.target.parentElement.children[1]; 
      let ul = e.target.parentElement.closest('ul');
      if(ul){
        ul.querySelectorAll('ul').forEach(function(item){
          item.style.minHeight = 0 + 'px';
        })
      }
      if(parseInt(getComputedStyle(el).minHeight) > 0){
        el.style.minHeight = 0 + "px";
      }else{
        el.style.minHeight =  el.scrollHeight + "px";
      }
    } catch (error) {
      return false;
    }
     return false;
}));



  document.querySelectorAll("ul ul li").forEach(el => el.addEventListener('click', function(e){

    e.preventDefault();
    e.stopPropagation();

    // const lists = document.querySelectorAll('ul ul')
    // lists.forEach(function(el){
      
    //     el.style.minHeight =  0 + "px"; 
    // })

    let el = null;
    let sh = 0;

     if(e.target.parentElement.hasChildNodes()){
      let ul = e.target.parentElement.querySelector('ul');
      if(e.target.parentElement.contains(ul)){
        el = e.target.parentElement.children[1];
        console.log(e.target.parentElement);
        console.log(e.target.parentElement.children[1]);
        sh  = el.scrollHeight;
      }
    }
      
    
      let elKey = parseInt(el.getAttribute('data-key'));

      let elli = e.target.parentElement.parentElement;

      let elH =  parseInt(el.getAttribute('data-sh'));
      let elliH =  parseInt(elli.getAttribute('data-sh'));

      // elli.style.minHeight = 0 + 'px';
      
      let elFirstChild = 0;
      if(el.hasChildNodes()){
        elFirstChild = el.children[0].scrollHeight;
        elFirstChild = parseInt(elFirstChild);
      }
    
      elli.style.minHeight = elliH + elFirstChild - elH + 'px';
      el.style.minHeight = elH + 'px';

     return false;
  }));
a {
    display: inline-block;
    width: 100%;
    height: 100%;
    padding: 5px 10px;

    color: white;
}

nav ul,
nav ul ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

nav ul {
    width: 200px;
    background: dodgerblue;
    position: relative;
}


nav ul ul {

    background: rgb(13, 130, 141);
    margin-left: 15px;
    border-left: 1px dashed white;
    transition: min-height .5s ease-in-out;

}

nav ul ul ul {
    background: rgb(1, 8, 8);
    margin-left: 15px;
    border-left: 1px dashed white;

}

nav ul ul ul ul {
    background: rgb(10, 41, 179);
    margin-left: 15px;
    border-left: 1px dashed white;
}
  <nav>
        <ul>
            <li><a href="javascript:void(0)">Home</a></li>
            <li><a href="javascript:void(0)">Dropdown 1 </a>
                <ul class="label-one">
                    <li><a href="javascript:void(0)"> Menu 1</a></li>
                    <li><a href="javascript:void(0)">Menu 2</a>
                        <ul class="label-two">
                            <li><a href="javascript:void(0)"> 1 Sub Menu 1</a></li>
                            <li><a href="javascript:void(0)"> 1 Sub Menu 2</a></li>
                            <li><a href="javascript:void(0)"> 1 Sub Menu 3</a> </li>
                        </ul>
                    </li>
                    <li><a href="javascript:void(0)">Menu 3</a>
                        <ul class="label-two">
                            <li><a href="javascript:void(0)"> 1 Sub Menu 1</a></li>
                            <li><a href="javascript:void(0)"> 1 Sub Menu 2</a></li>
                            <li><a href="javascript:void(0)"> 1 Sub Menu 3</a> </li>
                            <li><a href="javascript:void(0)"> 1 Sub Menu 3</a> </li>
                            <li><a href="javascript:void(0)"> 1 Sub Menu 3</a> </li>
                            <li><a href="javascript:void(0)"> 1 Sub Menu 3</a> </li>
                            <li><a href="javascript:void(0)"> 1 Sub Menu 3</a> </li>
                        </ul>
                    </li>
                    <li><a href="javascript:void(0)">Menu 4</a>
                        <ul class="label-two">
                            <li><a href="javascript:void(0)"> 1 Sub Menu 1</a></li>
                            <li><a href="javascript:void(0)"> 1 Sub Menu 2</a></li>
                            <!-- <li><a href="javascript:void(0)"> 1 Sub Menu 3</a> </li> -->
                        </ul>
                    </li>
                </ul>
            </li>
            <li><a href="javascript:void(0)">Dropdown 2 </a>
                <ul class="label-one" >
                    <li><a href="javascript:void(0)">Menu 2 </a>
                        <ul >
                            <li><a href="javascript:void(0)"> 2 Sub Menu 1</a></li>
                            <li><a href="javascript:void(0)"> 2 Sub Menu 2</a></li>
                        </ul>
                    </li>
                </ul>
            </li>
        </ul>
    </nav>

【问题讨论】:

  • 这对你有用吗
  • @Ac_mmi 这不是我要找的..
  • 你在找什么
  • 在我的代码中,您可以使用 class drop 添加子菜单并将其放在将 onclick 显示它的锚标记之后
  • @Ac_mmi 如果您在我的问题 sn-p 中单击 Dropdown 1Dropdown 2,您将看到它是如何工作的..

标签: javascript css animation


【解决方案1】:

这是我目前所能做的,如果它对你有用,我可以用更整洁的方式来做(我会尝试)

这里我做了一个类drop的div,我们可以添加&lt;a&gt;标签

function onLoad() {

  var drop = document.getElementsByClassName('drop');
  var adj_flag = 0;
  var Height = 0;
  var array = [];
  var c = [];
  var a = document.getElementsByTagName('a');
  var d;


  for (var i = 0; i < a.length; i++) {
    if (a[i].nextElementSibling != "DIV") {
      a[i].onclick = function() {
        var p = this.parentElement.children;
        for (var j = 0; j < p.length; j++) {
          if (p[j].nodeName == "DIV") {
            var decre = style_length(p[j].style.height);

            if (decre > 0) {
              p[j].style.height = "0px";
              var div = p[j];
              while (div.parentElement.nodeName == "DIV") {

                div = div.parentElement;

                div.style.height = (style_length(div.style.height) - decre) + "px";

              }
              var query_div = p[j].querySelectorAll("*");
              for (var k = 0; k < query_div.length; k++) {
                if (query_div[k].nodeName == "DIV") {
                  if (style_length(query_div[k].style.height) > 0) {
                    query_div[k].style.height = "0px";
                  }
                }
              }

            }
          }
        }
      }
    }
  }

  for (var i = 0; i < drop.length; i++) {

    drop[i].style.height = '0px';
  }

  for (var i = 0; i < drop.length; i++) {



    drop[i].previousElementSibling.onclick = function() {
      if (this.nextElementSibling.nodeName == "DIV") {
        var elem = this.nextElementSibling;

        var height_div = 0;
        if (elem.style.height == "0px") {
          var check = elem.parentElement.children;

          for (var i = 0; i < check.length; i++) {
            if (check[i].nodeName == "DIV" && check[i] != elem) {
              if (check[i].style.height != "0px") {

                c.push(check[i].previousElementSibling);


              }
            }
          }


          var height_calc = elem.children;
          for (var i = 0; i < height_calc.length; i++) {
            if (height_calc[i].nodeName == "A") {
              height_div += 38;
            }
          }


          elem.style.height = height_div + 'px';
          var flag = 0;
          var add_h = height_div;
          var changes;
          var q;
          if (c.length > 0) {

            for (var i = 0; i < c.length; i++) {
              if (style_length(c[i].nextElementSibling.style.height) != 0) {
                if (style_length(elem.style.height) == style_length(c[i].nextElementSibling.style.height)) {
                  changes = 0;
                } else {
                  if (style_length(elem.style.height) < style_length(c[i].nextElementSibling.style.height)) {
                    add_h -= style_length(c[i].nextElementSibling.style.height);
                  } else {
                    add_h -= style_length(c[i].nextElementSibling.style.height);
                  }

                }
              }
              c[i].nextElementSibling.style.height = "0px";
              q = c[i].nextElementSibling.querySelectorAll("*");
              for (var k = 0; k < q.length; k++) {
                if (q[k].nodeName == "DIV") {
                  q[k].style.height = "0px";
                }
              }
            }
          }

          while (elem.parentElement.nodeName == "DIV") {
            elem = elem.parentElement;
            var h = elem.offsetHeight + add_h;
            elem.style.height = h + 'px';

          }

          c.pop();

          flag = 0;
        } else {
          var query = elem.querySelectorAll('*');


          var sub_h = elem.clientHeight;
          elem.style.height = "0px";
          while (elem.parentElement.nodeName == "DIV") {
            elem = elem.parentElement;
            var h = elem.clientHeight - sub_h;
            elem.style.height = h + 'px';
          }

          for (var i = 0; i < query.length; i++) {
            if (query[i].nodeName == "DIV") {


              query[i].style.height = "0px";
            }
          }


        }
      }
    }
  }

  function style_length(A) {
    A = A.substring(0, A.length - 2);
    var s = parseInt(A);
    return s;
  }

}
* {
  margin: 0px;
  padding: 0px;
  color: white;
  font-family: 'arial';
}

.menu {
  position: absolute;
  margin-left: 100px;
  display: flex;
  flex-direction: column;
  width: 250px;
  min-height: 114px;
  overflow: hidden;
  background-color: black;
}

.menu a {
  background-color: black;
  text-decoration: none;
  color: white;
  padding: 10px;
}

.drop {
  background-color: black;
  transition: height 0.4s;
  display: flex;
  flex-direction: column;
  margin-left: 15px;
  height: 0px;
}
<body onload="onLoad()">
  <nav class="menu">
    <a href="#/">HOME</a>
    <a href="#/">DropDown-1</a>
    <div class="drop">
      <a href="#/" style="background-color: #00175A;">MENU-1</a>

      <a href="#/" style="background-color: #00175A;">MENU-2</a>
      <div class="drop">
        <a href="#/" style="background-color: #030E2E;">SUBMENU-1</a>
        <a href="#/" style="background-color: #030E2E;">SUBMENU-2</a>
        <div class="drop">
          <a href="#/" style="background-color:grey;">submenu-1</a>
          <a href="#/" style="background-color:grey;">submenu-2</a>
          <a href="#/" style="background-color:grey;">submenu-3</a>
        </div>
        <a href="#/" style="background-color: #030E2E;">SUBMENU-3</a>
        <div class="drop">
          <a href="#/" style="background-color:grey;">submenu-1</a>
          <a href="#/" style="background-color:grey;">submenu-2</a>
        </div>

      </div>
      <a href="#/" style="background-color: #00175A;">MENU-3</a>
      <div class="drop">
        <a href="#/" style="background-color: #030E2E;">SUBMENU-1</a>
        <a href="#/" style="background-color: #030E2E;">SUBMENU-2</a>
      </div>

    </div>
    <a href="#/">DropDown-2</a>
    <div class="drop">
      <a href="#/" style="background-color: #00175A;">MENU-2</a>
      <div class="drop">
        <a href="#/" style="background-color: #030E2E;">SUBMENU-1</a>
        <a href="#/" style="background-color: #030E2E;">SUBMENU-2</a>
      </div>

    </div>

  </nav>
</body>

【讨论】:

    【解决方案2】:

    document.querySelectorAll('li').forEach(element => element.addEventListener('click', event => {
      event.preventDefault();
      event.stopPropagation();
    
      let innerLists = element.querySelector('ul');
      if (innerLists) {
        if (!innerLists.classList.contains("show-list")) {
          document.querySelector("ul").querySelectorAll("ul").forEach(elm => {
            if (!isDescendant(elm, element)) {
              elm.classList.remove("show-list")
            }
          });
        }
    
        innerLists.classList.toggle("show-list");
      }
    }));
    
    function isDescendant(parent, child) {
      let node = child.parentNode;
      while (node != null) {
        if (node === parent) {
          return true;
        }
        node = node.parentNode;
      }
      return false;
    }
    a {
      display: inline-block;
      width: 100%;
      height: 20px !important;
      padding: 5px 10px;
      color: white;
    }
    
    nav ul,
    nav ul ul {
      list-style: none;
      margin: 0;
      padding: 0;
      display: flex;
      flex-direction: column;
      overflow: hidden;
    }
    
    nav ul {
      width: 200px;
      background: dodgerblue;
    }
    
    nav ul ul {
      background: rgb(13, 130, 141);
      margin-left: 15px;
      border-left: 1px dashed white;
      /* height: 10px; */
      transition: max-height .5s ease-in-out;
    }
    
    nav ul ul ul {
      background: rgb(1, 8, 8);
      margin-left: 15px;
      border-left: 1px dashed white;
      /* height: 10px; */
      transition: max-height .5s ease-in-out;
    }
    
    nav ul ul ul ul {
      background: rgb(10, 41, 179);
      margin-left: 15px;
      border-left: 1px dashed white;
      /* height: 10px; */
      transition: max-height 0.5s ease-out;
    }
    
    ul li ul {
      max-height: 0 !important;
      transition: max-height 1s ease-in-out;
      animation-iteration-count: infinite;
      animation-direction: alternate;
    }
    
    .show-list {
      max-height: 500px !important;
      transition: max-height 1s ease-in-out;
      animation-iteration-count: infinite;
      animation-direction: alternate;
    }
    <nav>
      <ul>
        <li><a href="javascript:void(0)">Home</a></li>
        <li><a href="javascript:void(0)">Dropdown 1 </a>
          <ul>
            <li><a href="javascript:void(0)"> Menu 1</a></li>
            <li><a href="javascript:void(0)">Menu 2</a>
              <ul>
                <li><a href="javascript:void(0)"> 1 Sub Menu 1</a></li>
                <li><a href="javascript:void(0)"> 1 Sub Menu 2</a></li>
                <li><a href="javascript:void(0)"> 1 Sub Menu 3</a></li>
              </ul>
            </li>
            <li><a href="javascript:void(0)">Menu 3</a>
              <ul>
                <li><a href="javascript:void(0)"> 1 Sub Menu 1</a></li>
                <li><a href="javascript:void(0)"> 1 Sub Menu 2</a></li>
                <!-- <li><a href="javascript:void(0)"> 1 Sub Menu 3</a> </li> -->
              </ul>
            </li>
          </ul>
        </li>
        <li><a href="javascript:void(0)">Dropdown 2 </a>
          <ul>
            <li><a href="javascript:void(0)">Menu 2 </a>
              <ul>
                <li><a href="javascript:void(0)"> 2 Sub Menu 1</a></li>
                <li><a href="javascript:void(0)"> 2 Sub Menu 2</a></li>
              </ul>
            </li>
          </ul>
        </li>
      </ul>
    </nav>

    注意:对于一个简单的下拉任务,您不必编写大量此类 JS 代码。

    【讨论】:

    • 它不会折叠以前的ul 列表...如果您在我的问题 sn-p 中单击Dropdown 1Dropdown 2,您将看到它是如何工作的..
    • @noor 现在检查
    • 首先感谢您的回复...但是动画无法正常工作...如果您与我的示例Dropdown 1Dropdown 2 进行比较...我想您可以弄清楚...这就是我写了很多代码的原因..也许还有其他方法..
    • 请再检查一遍
    • 你使用 max-height: 500px !important; ,如果存在更多 li 项目会产生 bug ...
    猜你喜欢
    • 1970-01-01
    • 2019-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-09
    相关资源
    最近更新 更多