首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用html、css和javascript在简单菜单中冒泡

使用html、css和javascript在简单菜单中冒泡
EN

Stack Overflow用户
提问于 2018-08-25 18:04:12
回答 1查看 635关注 0票数 3

在下面的简单菜单代码中,如果子菜单是展开/显示的,那么我需要在几种情况下折叠该子菜单:

当主菜单或子菜单LI被单击时

  1. 当视口大于定义的最小宽度时
  2. 当单击发生在屏幕上的其他位置时

只要我不为mainMenuID元素声明addEventListener,数字2就可以工作,数字1就可以工作。由于某些原因,当我为任何mainMenuID元素添加事件侦听器时,它优先于任何其他元素,因此单击Portfolio或其子菜单项以外的主菜单项时,会展开和折叠菜单,但单击submenuID或ulID不会执行任何操作。一旦我删除了mainMenuID的eventlistener,单击submenuID或ulID展开/折叠子菜单。

第二个问题是,如何将单击事件侦听器添加到页面的其余部分,以便在显示子菜单时,单击会折叠子菜单。

谢谢!

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
</head>

<style media="screen">
body{
  background-color: black;
}

nav ul {
    position: relative;
    text-align: left;
}

nav ul li {
    display: block;  /* WHAT????  REMOVING THIS ACTUALLY MAKES TEXT-DECORATIONS REAPPEAR.... WHY???*/
}

nav a {
    text-decoration: none;
}

/* Hide dropdowns by default */
nav ul ul {
    position: relative;
    display: none;
    left: 0;
}

/* Display Dropdowns on Click */
    nav ul li.showSubmenu > ul {
    display: block;
    position: relative;
    width: 30%;
}

.menu a {
    text-decoration-style: none;
    text-decoration: none;
    background-color: black;
    color: white;
}

.menu a:hover{
    background-color: white;
    color: black;
}
</style>

<body>
    <nav id="mainMenuID" class="menu">
        <ul>
            <li class="menuItem"><a href="#">Home</a></li>
            <li class="menuItem"><a href="#">About</a></li>
            <li id="submenuItem" class="submenu_class"><a href="#"><span id="submenuID">Portfolio ▼</span></a>
            <ul id="ulID">
                <li><a href="#">Landscape</a></li>
                <li><a href="#">Architecture</a></li>
                <li><a href="#">Animal</a></li>
                <li><a href="#">Other</a></li>
            </ul>
            </li>
            <li class="menuItem"><a href="#">Information</a></li>
            <li class="menuItem"><a href="#">Contact</a></li>
       </ul>
    </nav>


<script>
function openSubmenu() {
    if (document.getElementsByClassName('showSubmenu').length == 0){
      document.getElementById("submenuItem").classList.toggle("showSubmenu");
      document.getElementById("submenuID").textContent = "Portfolio ▲";
    } else {
      document.getElementById("submenuItem").classList.toggle("showSubmenu");
      document.getElementById("submenuID").textContent = "Portfolio ▼";
    }
}


function resetSubmenu() {
    var submenuElements = document.getElementsByClassName('submenu_class showSubmenu');
    for (var i = 0; i < submenuElements.length; i++) {
    submenuElements[i].setAttribute('class', 'submenu_class');
    document.getElementById("submenuID").textContent = "Portfolio ►";
    }
}

function screenWidthFunction(x) {
    if (x.matches) {//if it's a narrow screen
        document.getElementById("submenuID").textContent = "Portfolio ▼";
        document.getElementById("ulID").addEventListener("click", openSubmenu, true);
        document.getElementById("submenuID").addEventListener("click", openSubmenu, true);
        document.getElementById("mainMenuID").addEventListener("click", openSubmenu, true);
    } else {
        resetSubmenu();
        document.getElementById("submenuID").textContent = "Portfolio ►";
        document.getElementById("ulID").removeEventListener("click", openSubmenu);
        document.getElementById("submenuID").removeEventListener("click", openSubmenu);
        document.getElementById("mainMenuID").removeEventListener("click", openSubmenu);
      }
   }

    var x = window.matchMedia("(max-width: 480px)");
    screenWidthFunction(x);
    x.addListener(screenWidthFunction);
</script>

<> Hi Robidu,我只使用CSS就可以使用这个菜单,但我被引导使用JS来实现它的一些功能,这导致大多数CSS无法工作。因此,在冰川速度下,我一直在尝试在飞行中学习JS。信不信由你,从视频、W3Schools等中学习…。在过去5到6周的大部分时间里,我一直在写、重新编写和拼凑这个菜单。太可笑了。看起来您理解JS,并且对JS非常熟悉。这需要我再花几个星期的时间来弄清楚如何实施你的所有建议,而在此过程中,我很可能会破坏已经起作用的东西。有没有什么方法我可以请你为我提供他们需要去哪里的代码片段,或者只是更具体的建议,以节省我的痛苦。下面我摘录了你的文章中我有疑问的部分(由于评论的字符限制,我必须将它们分成多个评论):

  1. “…你应该使用CSS来隐藏子菜单,因为我认为这是默认的。“问:是的,这是默认设置。我以为我已经在“nav ul li.showSubmenu > ul {…}“在我的CSS.
  2. 中”…实现在DOMContentReady上触发的初始化阶段,以设置支持基础结构。“问:这一点,我永远不知道如何弄清楚自己。
  3. “…需要一个指示菜单是否打开的标志,以便处理程序可以做出相应的反应…省去了“切换”…的麻烦将菜单的状态设置为…“问:我认为“showSubmenu”类的“切换”就是一种“旗帜”。如何以及在何处使用变量来代替切换?
  4. “…省去你自己的…反复附加和删除事件侦听器。“,然后”如果菜单被隐藏,它将不会获得任何事件。“问:你是说将监听器赋给JS代码中的任何地方的变量吗?我是否仍然需要在现在使用侦听器的相同位置以相同的方式引用这些变量?
  5. “…将检查鼠标事件的事件侦听器附加到在此处打开子菜单的项。“问:你是说除了我在id=“submenuID”上的那个听众?你的建议会有什么不同?
  6. “…将调整大小事件处理程序附加到执行此检查的窗口...“问:我从W3的例子中裁剪了屏幕宽度代码。如何/在何处使用innerWidth/innerHeight是different?
  7. “…将冒泡阶段设置为true以拦截事件“。问:如果你将一种方法应用于菜单系统中的菜单项,另一种方法应用于页面上的其他元素,等等,我一直找不到任何关于冒泡工作的解释。我理解基础知识,但不能理解当所有三个监听器都在单击菜单项时used.
  8. “Collapsing菜单时,它为什么不能在这个简单的菜单上工作。…为每个单独的菜单项附加一个事件处理程序(最好的位置是菜单内的链接)。问:我必须为每个LI分配一个ID吗?
  9. 总体问题:我将NAV元素与UL和LIs一起使用,因为我被告知它是屏幕阅读器最容易访问的元素。有没有更好的方法来做我想用这个菜单做的事情,或者我在某种程度上是正确的。--

我真诚地为所有后续问题/澄清道歉,但我真诚地在这件事上旋转我的轮子,在波涛起伏的海面上,戴着一个蒙眼的…。以及你可以加入的任何其他类比。

我真的很感激你能提供任何具体的代码来演示你的建议的细节。(或者甚至给我举一些例子,这样我就可以试着找出它们了)。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-08-25 20:01:52

稍微调整一下就可以解决这个问题了。

首先,你应该使用CSS来隐藏子菜单,因为我认为这是默认的。此外,您应该实现一个在DOMContentReady上触发的初始化阶段,以设置支持基础设施。这样,您就省去了重复附加和删除事件侦听器的麻烦。您可能希望将检查鼠标事件的事件侦听器附加到在此处打开子菜单的项。您还需要一个指示菜单是否打开的标志,以便处理程序可以做出相应的反应(这样,您就可以省去“切换”之类的问题,而且如果您需要执行任何其他检查,您还可以立即获得菜单的状态)。在这里,一个简单的变量就可以解决这个问题。积极的一面:如果菜单是隐藏的,它根本不会得到任何事件。

如果您对窗口大小感兴趣,我建议您改为使用window.innerWidth / window.innerHeight,因为这是您获得的一个数值,并且可以很容易地与所需的最小大小进行比较。只需将调整大小事件处理程序附加到执行此检查的窗口,即可完成设置。如果窗口大小低于您的最小值,只需强制菜单折叠即可。

至于在用户单击文档中的任何位置时折叠菜单,将查找鼠标单击/按键的事件侦听器附加到document对象可以在此处完成此操作(将冒泡阶段设置为true,以便在任何其他事件发生之前拦截事件)。

单击菜单项时折叠菜单的最佳方法是将事件处理程序附加到仅关闭菜单的每个菜单项(最好是菜单内的链接-将冒泡阶段设置为false)。

编辑:

我现在已经通过使用HTML和CSS进行了一些修改,这就是我想出的方法(请注意,我还将文件转换为XHTML -但这取决于您是否愿意这样做):

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xml:lang="en">
<head>
<title>Submenu Test Case</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<style type="text/css">
body {
  background-color: black;
  color: white;
  }

aside {
  width: 15em;
  float: left;
  }

nav ul {
  position: relative;
  text-align: left;
  list-style: none;         /* Kills any list decoration */
  }

nav ul ul {
  position: relative;
  left: 0;
  }

nav a {
  text-decoration: none;
  }

/* This ARIA attribute can greatly improve accessibility and can also be used
   to actually hide elements just by tying "display: none;" to it... */
[aria-hidden="true"] {
  display: none;
  }

.menu a {
  color: white;
  }

.menu a:hover, .menu span:hover {
  background-color: white;
  color: black;
  }

/* Style definitions that override settings for mobile devices go here! */
@media screen and (min-width: 480px)
  {
/* Reposition the submenu if it's on a sufficiently wide window... */
  nav ul li > ul {
    position: absolute;
    margin-top: -1.2em;
    left: 7em;
    }
  }
</style>
<script type="application/javascript">
/* <![CDATA[ */
var submenu_open = false;   // Has the submenu been opened?
var need_mobile = false;    // Are we on a narrow window?

// Takes care of hiding and showing the submenu
function ToggleMenu(p_event)
  {
// Do not activate e. g. on a right click...
  if(p_event.button != 0)
    return;

  if(submenu_open)
    {
// If the submenu has previously been open, close it (and adjust the
// controlling menu item if necessary)
    document.getElementById('sub1').setAttribute('aria-hidden', 'true');
    if(window.innerWidth < 480)
      document.getElementById('sub-item1').childNodes[0].childNodes[0].data = 'Portfolio ▼';
    }
  else
    {
// If the submenu has previously been closed, open it (and adjust the
// controlling menu item if necessary)
    document.getElementById('sub1').setAttribute('aria-hidden', 'false');
    if(window.innerWidth < 480)
      document.getElementById('sub-item1').childNodes[0].childNodes[0].data = 'Portfolio ▲';
    }

// This prevents the document's root node (i. e. the document object) from
// seeing the event when clicking on the superordinate item for the submenu...
  p_event.stopPropagation();

  submenu_open = !submenu_open;
  }

// Triggered upon clicking anywhere inside of the document...
function CloseMenu(p_event)
  {
  if(!submenu_open)
    return;

  document.getElementById('sub1').setAttribute('aria-hidden', 'true');
  if(window.innerWidth < 480)
    document.getElementById('sub-item1').childNodes[0].childNodes[0].data = 'Portfolio ▼';
  submenu_open = false;
  }

function CheckWindowSize(p_event)
  {
  if(window.innerWidth < 480)
    {
    if(need_mobile)
      return;

// On a mobile device, insert the submenu into the main one...
    if(submenu_open)
      document.getElementById('sub-item1').childNodes[0].childNodes[0].data = 'Portfolio ▲';
    else
      document.getElementById('sub-item1').childNodes[0].childNodes[0].data = 'Portfolio ▼';
    }
  else
    {
    if(!need_mobile)
      return;

// If the window is wide enough, we can display the submenu next to the main
// one...
    document.getElementById('sub-item1').childNodes[0].childNodes[0].data = 'Portfolio ►';
    }

  need_mobile = !need_mobile;
  }

// Initialization sequence (adds a few event handlers)
document.addEventListener('DOMContentLoaded', function (p_event) {
  document.getElementById('sub-item1').addEventListener('click', ToggleMenu, false);
  window.addEventListener('resize', CheckWindowSize, false);
  document.addEventListener('click', CloseMenu, false);

// If we are on a mobile device, adjust the text of the menu item.  
  if(window.innerWidth < 480)
    {
    need_mobile = true;
    document.getElementById('sub-item1').childNodes[0].childNodes[0].data = 'Portfolio ▼';
    }
  }, false);
/* ]]> */
</script>
</head>
<body>
<header><h1>Submenu Test Case</h1></header>
<aside>
<nav class="menu">
  <ul>
    <li class="menuItem"><a href="javascript:alert('\'Home\' triggered!');">Home</a></li>
    <li class="menuItem"><a href="javascript:alert('\'About\' triggered!');">About</a></li>
    <!-- Assume normal operation here (window width >= 480 pixels) so the
         text is set accordingly...
         Please note that I have removed some extraneous elements and
         attributes. -->
    <li class="submenu" id="sub-item1"><span>Portfolio ►</span>
    <ul id="sub1" aria-hidden="true">
      <li><a href="javascript:alert('\'Landscape\' triggered!');">Landscape</a></li>
      <li><a href="javascript:alert('\'Architecture\' triggered!');">Architecture</a></li>
      <li><a href="javascript:alert('\'Animal\' triggered!');">Animal</a></li>
      <li><a href="javascript:alert('\'Other\' triggered!');">Other</a></li>
    </ul>
    </li>
    <li class="menuItem"><a href="javascript:alert('\'Information\' triggered!');">Information</a></li>
    <li class="menuItem"><a href="javascript:alert('\'Contact\' triggered!');">Contact</a></li>
  </ul>
</nav>
</aside>
<main />
</body>
</html>

请参阅(X)HTML中的注释,了解那里发生了什么。通过这样做,我发现我可以极大地简化我再次提到的方法,因此它可以归结为三个事件:

click on >单击菜单项:打开或关闭菜单单击任何地方:关闭submenu

  • Mouse

至于你的问题..。

AD1:我对你提供的CSS做了一些调整。我去掉了一些定义,并将隐藏任何元素绑定到aria-hidden属性(如果该属性设置为true,则不显示该元素)。Said attrtibute在提高可访问性方面也有很大帮助。在这个例子中,如果你在屏幕上看不到它,那么屏幕阅读器也不会显示它。

广告2:它的设置相当简单。只需在主执行路径中包含document.addEventListener('DOMContentLoaded', function (p_event) { }, false);,并将需要设置的任何内容添加到函数中即可。这对于所谓的不显眼的JavaScript (即JavaScript本身在需要的地方将钩子附加到文档,而不是将它们硬编码到(X)JavaScript中)来说尤其重要。

AD3.:您可以通过一个简单的变量(一个布尔值,用于指示菜单是否打开)来完成此操作。然后,您可以快速检查菜单的状态,而不必查询DOM。

AD4:这是非常繁琐和昂贵的,所以处理程序只附加一次。其余的应该由控制逻辑来决定是否有任何事件被静默忽略(如果不满足某些条件,则只返回)。

AD5:它接受您实现的那种处理程序,但我对它进行了一些简化,以避免在不必要的地方调用DOM (它求助于前面提到的标志),此外,它还考虑了窗口的宽度来调整文本。

ad 6.:innerWidth / innerHeight是DOM可以轻松返回的数值。我不知道你的方法,但我认为它似乎有点昂贵,而且当你将值存储在一个变量中时,你可以对它执行多次检查(例如,如果你需要检查不同的宽度/高度),这只需要简单的比较。您的方法将要求您重置匹配条件。

AD7:我需要在这里纠正我自己,因为通过仔细研究你的问题,我发现所有东西(即addEventListener的第三个参数)都应该设置为false。否则,执行的顺序会变得混乱,或者一些链接一开始就看不到事件。

公元8.:也被证明是不必要的。我最初的答案来自我在JavaScript中实现的上下文菜单,但由于它的性质,我不得不求助于这些处理程序来关闭它。这里的情况有点不同,所以只需省略这些处理程序就可以简化。

公元9:你实际上选择了最好的方法。在实现导航时,我也使用这种方法。

我希望我能把你们的一些问号变成感叹号。但是,如果您还有任何问题,请随时提出。没有什么比没有回答的问题更糟糕的了。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52016151

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档