JavaScript 点击打开和关闭菜单,不使用 jQuery

3
我想要一个菜单,可以通过点击打开和关闭,类似于悬停菜单,但需要点击才能打开和关闭。我有三个可见的列表项,并带有子菜单。这些子菜单通过css中的display:none进行隐藏。使用关键字“this”和for循环检查任何“ul”是否有多个项目,然后当单击时列表将打开。根据我之前得到的帮助,我尽力理解了这段代码。现在我已经阅读并观看了Buckysroom的教程,感觉我至少对数组和代码中的所有内容有了更深的理解。目前,我的代码如下。
function showMenu(parentElement){
    var uls= parentElement.getElementsByTagName("ul");
    if (uls.length > 0)
        uls[0].setAttribute("style","display: block");

 }

function load(){ 
    var lis = document.getElementsByTagName("li"); 
    for (var i = 0; i < lis.length; i++) {
        lis[i].addEventListener("click", function(){
            showMenu(this);
        }); 
    }
}
据我所理解,最后的 'for' 循环,我看到这段代码打开了任何数组,或者像是有超过 1 个 ( [0] ) 项的任何 'li',因为在数组中 0 是 1,并循环查看它是否有子元素。如果有,它将打开 'this' 'li' 的 'ul'。

由于 load 函数包含 showMenu 函数,而我已经学会了一点,在函数内部使用函数,而不是复制自己,使用数组和变量,并以某种方式相互分配。Buckysroom 的教程至少帮助我理解了这么多。

现在... 我的问题是我不知道足够的 Javascript 来理解这个问题,我宁愿不使用 jQuery,而是学习如何使用纯 Javascript 实现这个目标。

任何指针都会很有帮助,我已经尝试了以下方法;

给我的三个 ul 添加唯一的 Id,这样我就知道可以用上面的代码打开它们,我也能用另一个代码将它们关闭,将其设置为 "display:none"。

那么问题在于我没有再次打开它们的机会,我明白我缺少一些部分,例如stopPropagation或者使用addEventListener-Click来完成第二部分。正如你所理解的,addEventListener是我从这里的代码中得到的。
 function Meny1(){

    var unorderedList = document.getElementById("ul_1");

            var lis = unorderedList.getElementsByTagName("li");
            for (var i = 0; i < lis.length; i++) {

            lis[i].setAttribute("style","display: none");

            }
}

我发现可以使用数字来指定每个菜单项,例如[23],而不是[i],以定位单个菜单项,请复制该行并进行如下修改:

lis[23].setAttribute("style","display: none");
lis[24].setAttribute("style","display: none");

但据我所知,这是一种不好的做法,因为如果我要添加另一个菜单项或删除一个菜单项,这样做将非常糟糕,而且也会产生大量的复制编码。

我的想法是,我想要像这样的东西:

html:
<div id ="cssmenu"></div>
<ul id="ul_1"><li>I have many li's in each 'ul'</li></ul>
<ul id="ul_2"><li>I have many li's in each 'ul'</li></ul>
<ul id="ul_3"><li>I have many li's in each 'ul'</li></ul>

样式表:

#cssmenu{display:block;}
#cssmenu ul li ul{display:none}
我的想法是JS应该如何实现,我并没有使用类(因为w3c验证器指出我不应该这样做)。
function showAndCloseMenu1(){
var ul_1 = document.getElementbyId("ul_1");
    if(mouseclicked on ul_2 || mouseclicked on ul_3){
        close.ul_1(this)
    }
        if(mouseClicked ul_1){
         style.display = "block";
        }
}

然后对于ul_2和ul_3同样如此,我还没有足够的能力去考虑将所有内容实现到一个代码中,但当然我知道这是可能的,可以使用全局变量和属性来实现。

有人能帮助我吗?

我尝试过使用jQuery,但没有成功,而且正如我所说,我宁愿不使用它,因为我渴望充分学习Javascript!我可以阅读Javascript,而jQuery对我来说只是一堆美元符号,里面有简化的Javascript。

http://fiddle.jshell.net/ufcsccy3/

这里有一个fiddle,在浏览器中菜单无法正常工作,但如果您在那里看的话,就可以理解,它是左侧的菜单。

我该如何使用Javascript在我的导航中实现显示/隐藏功能? 我想得到正确的方向,我认为类别没有多大区别,但也许可以节省一些编码空间。

感谢任何对此的帮助!我似乎无法想出一个可行的解决方案! 我希望当我第一次单击ul_1时,它会打开。如果我再次单击它,我希望它关闭。 如果ul_1已打开,并且我单击ul_2或ul_3,我希望打开该标签并再次关闭ul_1,这是我认为比较标准的菜单导航。

2个回答

3

只需为打开菜单切换一个ID。一种方法是使用 onclick,它可以完成所有操作。

function showmenu(elem) {
  // Clear any currently open menu
  var openMenu = document.getElementById("activeMenu");
  if (openMenu) {
    openMenu.removeAttribute("id");
    // Stop if we're just closing the current menu
    if (openMenu === elem) {
      return;
    }
  }

  // Only apply it if the element actually has LI child nodes.
  // OPTIONAL: Will still work without if statement.
  if (elem.getElementsByTagName("li").length > 0) {
    elem.setAttribute("id", "activeMenu");
  }
}
ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
ul li {
  float: left;
  padding: 0 10px;
}
ul ul {
  display: none;
}
ul ul li {
  float: none;
}
#activeMenu ul {
  display: block;
}
<ul>
  <li onclick="showmenu(this)">Menu Item 1</li>
  <li onclick="showmenu(this)">Drop Down 1
    <ul>
      <li>DD1 Item 1</li>
      <li>DD1 Item 2</li>
    </ul>
  </li>
  <li onclick="showmenu(this)">Drop Down 2
    <ul>
      <li>DD2 Item 1</li>
      <li>DD2 Item 2</li>
    </ul>
  </li>
</ul>

请注意,我仅仅是为了简单起见使用了onclick。添加你所做的点击事件才是正确的方式。

看起来有点可行,但我遇到了一个奇怪的问题,我的菜单失去了所有样式: o 我已经在我的 CSS 中分配了#cssmenu ul 等。并尝试更改 js 中的 activeMenu 为 cssmenu,但没有运气。我是否需要为所有的 CSS 样式都加上类似于 cssmenu 的东西,并将所有这些样式复制到 #activeMenu 中?因此,在菜单中重复 CSS 样式?代码看起来是有效的,并且解释得非常好,非常感谢 :) - sunto
你是否已经在每个单独的LI元素上使用了ID?还是只在实际菜单上有一个ID?如果一开始LIs上没有任何东西,您应该只需将#activeMenu添加到CSS中,一切都保持不变。 - David
注意,我还将第一个showmenu更改为showMenu,所以应该是正确的CSS吗?@David - sunto
不要使用onclicks,参见我帖子的最后一行。你在load方法中的做法更好,尽管你可能只想将它添加到直接子元素中。名称无关紧要,只要一切匹配即可。如果样式仍然被清除,请使用调试器工具查看哪些内容正在覆盖它们。#activeMenu应仅用于使其子ul可见。其他样式应来自它们原始位置。 - David
好的,但是它会在onclick事件中起作用吗?首先尝试让它正常工作,因为在我确认它能正常运行之前,我不敢随意更改你的代码。CSS菜单里不能有任何id吗?我注意到那里有一些带有id的按钮。 - sunto
显示剩余5条评论

0
function showMenu(elem) {
      // Clear any currently open menu
      var openMenu = document.getElementById("activeMenu");
  if (openMenu) {
        openMenu.removeAttribute("id");
        // Stop if we're just closing the current menu
        if (openMenu === elem) {
          return;
    }
  }

      // Only apply it if the element actually has LI child nodes.
      // OPTIONAL: Will still work without if statement.
      if (elem.getElementsByTagName("ul").length > 0) {
        elem.setAttribute("id", "activeMenu");
      }
    }

        function showSubMenu(elem) {
      // Clear any currently open menu
          var openMenu = document.getElementById("activeMenu");
      if (openMenu)
        openMenu.removeAttribute("id");
      var openSubMenu = document.getElementById("activeSubMenu");
      if (openSubMenu) {
        openSubMenu.removeAttribute("id");
        // Stop if we're just closing the current menu

      }

      // Only apply it if the element actually has LI child nodes.
      // OPTIONAL: Will still work without if statement.
      if (elem.getElementsByTagName("ul").length > 0) {
        elem.setAttribute("id", "activeSubMenu");
      }
    }
        function showLastSubMenu(elem) {
      // Clear any currently open menu
          var openMenu = document.getElementById("activeMenu");
      if (openMenu)
        openMenu.removeAttribute("id");
      var openSubMenu = document.getElementById("activeSubMenu");
      if (openSubMenu) 
        openSubMenu.removeAttribute("id");
        // Stop if we're just closing the current menu
    var openLastSubMenu = document.getElementById("activeSubMenu");
      if (openLastSubMenu) {
        openLastSubMenu.removeAttribute("id");

}
      // Only apply it if the element actually has LI child nodes.
      // OPTIONAL: Will still work without if statement.
      if (elem.getElementsByTagName("ul").length > 0) {
        elem.setAttribute("id", "activeLastSubMenu");
      }
    }

我发布了完整的代码,这个可点击菜单解决方案得到了@David的很多帮助,非常感谢:)

css项#someMenu ul、#somemenu ul li和#someMenu ul ul必须更改为类,因此是.someMenu ul等。 #activeMenu > ul { display: block; }

#activeSubMenu > ul {
  display: block;
}
#activeLastSubMenu > ul {

  display: block;
}  

在HTML中,

<nav id ="someMenu" class="someMenu">
function showMenu on the first level li's, 
function showSubMenu for next level
function showLastSubMenu for the last sub's (I had max 3 levels)

有很多重复的代码,所以我将尝试使用数组和addEventListener来减少代码量,正如您在答案中所说的那样,这样更正确!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,