【问题标题】:Trouble adding focus event to element with javascript使用javascript向元素添加焦点事件时遇到问题
【发布时间】:2015-12-19 21:26:22
【问题描述】:

我刚开始学习 Javascript(刚开始),当焦点应用于元素时,我在尝试显示隐藏的“子导航”菜单时遇到问题。我保持它非常基本(我认为)。

这个想法与在悬停时显示隐藏的“子导航”菜单相同。当用户对元素和焦点应用标签时,菜单显示并且菜单中的链接变得可聚焦。当用户关闭菜单时,菜单会再次隐藏。我希望这发生在任意数量的导航元素上。

HTML:

<nav role="navigation">
   <ul>
      <li><a href="#">Link 1</a></li>
      <li><a href="#" class="has-dropdown">Link 2</a>
         <ul class="dropdown">
            <li><a href="#">Link 2a</a></li>
            <li><a href="#">Link 2b longer</a></li>
            <li><a href="#">Link 2c longest text</a></li>
         </ul>
      </li>
      <li><a href="#">Link 3</a></li>
      <li><a href="#">Link 4</a></li>
   </ul>
</nav>

不确定你是否需要它,但这里是 CSS:

nav[role=navigation] {
  width: 100%;
  background: #505050;
  font-family: Oswald,sans-serif;
  font-weight: 200;
}

nav[role=navigation] ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-flex-wrap: wrap;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
  -webkit-justify-content: flex-start;
  -ms-flex-pack: start;
  justify-content: flex-start;
}

nav[role=navigation] ul li {
  -webkit-flex: 0 1 auto;
  -ms-flex: 0 1 auto;
  flex: 0 1 auto;
  text-align: center;
  padding: .8333rem;
  border-right: 1px solid #252525;
  position: relative;
}

nav[role=navigation] ul li:last-of-type {
  border-right: none;
}

nav[role=navigation] ul li:hover a + ul {
  display: block;
}

nav[role=navigation] ul ul {
  list-style: none;
  position: absolute;
  top: 100%;
  left: 0;
  background: #252525;
  padding: 0;
  width: 200%;
  text-align: left;
  display: none;
}

nav[role=navigation] ul ul.active {
  display: block;
}

nav[role=navigation] ul a {
  padding: 0 1rem;
  color: #fff;
  text-decoration: none;
}

nav[role=navigation] ul a:focus,
nav[role=navigation] ul a:hover {
  text-decoration: underline;
  color: #ccc;
}

Javascript:

var topLevel = document.getElementsByClassName("has-dropdown");

for (var i = 0; i < topLevel.length; i++) {
   topLevel[i].onfocus = function() {
      console.log("you have activated the dropdown");
      topLevel.nextElementSibling.className = "active";
   }
}

当我点击触发此链接的链接时,我会在任何具有子菜单但子菜单不显示的链接上正确获取日志消息。当我从控制台运行时,出现错误:

“无法设置未定义的属性“className”。”

我相信这与作为数组的变量有关,因为如果我设置 topLevel 的索引,例如 topLevel[0],它可以完美地工作。

我想使用原版 JS。没有 JQuery。

我搜索了类似的问题,但找不到任何让我头疼的答案或仅提供 JQuery 解决方案。

我看过:

Drop down menu to hide on click event
For-each over an array in JavaScript? --> 这个让我脑洞大开。
Target items in an array on click?
How to split an array with retrieved values from DOM

答案可能隐藏在上述帖子之一中,但如果是,我找不到。

【问题讨论】:

  • 我在 JSFiddle 上尝试了你的代码,它按预期工作:jsfiddle.net/chktsx8h
  • 我看了你的小提琴,它在那里不起作用。当 link2 获得焦点时,子菜单不会出现。
  • 我认为是浏览器,对不起。我尝试使用 Chrome。

标签: javascript html arrays dom-events


【解决方案1】:

在现代浏览器中你应该添加一个监听器:

var topLevel = document.getElementsByClassName("has-dropdown");

for (var i = 0; i < topLevel.length; i++) {
   topLevel[i].addEventListener('focus',function(event) {
      console.log("you have activated the dropdown");
     event.currentTarget.nextElementSibling.className  = "active";
   },false);
}

参考:addEventListener not working in IE8

旧浏览器

var topLevel = document.getElementsByClassName("has-dropdown");

for (var i = 0; i < topLevel.length; i++) {
    if (topLevel[i].addEventListener) {
          topLevel[i].addEventListener('focus',function(event) {
          console.log("you have activated the dropdown");
          event.currentTarget.nextElementSibling.className  = "active";
       },false);
    }
    else {
        topLevel[i].attachEvent("focus", function(event) {
        console.log("you have activated the dropdown");
        event.currentTarget.nextElementSibling.className  = "active";
   });
}

【讨论】:

  • 删除课程由您(何时)决定,但请参考:.classList.remove("active");
  • 我之所以避开addEventListener,是因为我需要支持IE8。糟透了,我知道,但这是必要的。如果对像我这样的新手来说,提供对悲伤浏览器的支持工作量太大,我将默认使用这种方法。
  • 啊,那对 IE 来说是有道理的。您可以查看 jQuery 代码以了解他们如何针对事件进行规范化(并且仍然不使用 jQuery)...它在那里经过了很好的审查和测试 - 比如在 1.11.x 版本中。
  • 感谢您更新答案。第一部分效果很好。明天早上我将测试第二部分。我有它添加类并正确删除类。现在我只需要弄清楚如何从二级子a 定位父ul 以在子菜单中切换时保持菜单可见。有什么原因我不能使用应用于不同元素的第二个焦点事件,比如子菜单中的链接?
  • 通常对于“菜单”类型的元素,这些是通过鼠标悬停或鼠标输入/鼠标输出完成并单击(以选择菜单链接) - 或“键”,例如当元素被按下时的返回键专注......真的取决于你,但看看其他人如何做菜单而不是你的惊喜
【解决方案2】:

我在我的项目https://github.com/arthurdd/scales/blob/master/index.js#L60遇到了同样的问题

基本上我所做的是定义一个函数add_listeners_all(如果你只做一次,你可能不需要这样的函数)

这是代码

function add_listeners_all( selector, fun ) {
    Array.prototype.slice.apply(document.querySelectorAll(selector)).forEach(el) {
        el.addEventListener('click', fun);
    });
});

我不记得我是如何做到这一点的语义,但它工作得很好,正如你在现场演示中看到的那样 http://backtick.town/~jay/scales (正在开发中,不要指望它还能工作)

如您所见,您可以将 document.querySelectorAll(selector) 替换为您的 toplevel 数组,并将 fun 替换为您的函数。

再一次,这段记忆对我来说都很模糊,所以这可能行不通。如果它不起作用,请随意投反对票并向我发泄你的愤怒。

【讨论】:

  • 不确定如何应用。你说“我不记得我是如何做到这一点的语义,但它工作得很好,正如你在现场演示 backtick.town/~jay/scales 中看到的那样”,但随后声明“(正在开发中,不要指望它工作呢)”。我点击了您的项目和链接,但没有看到与我的问题相关的任何内容。也许我错过了。你能进一步解释一下吗?正如我所说,我刚开始学习,可能没有正确连接点。
  • 对不起。我处理给元素事件监听器的方式是循环遍历它们并设置事件监听器,就像你在这里尝试做的那样。您可以通过使用 forEach 循环和addEventListener 轻松应用此技术。
  • 我会调查的。
  • 像我尝试做的那样使用简单的 for 循环是否存在根本缺陷?我宁愿这样做。回到最初的问题;为什么这不起作用?
  • 查看您的代码似乎是toplevel[i].onfocus 行导致了问题。 blabla.onfocus 和朋友只能处理一个事件监听器。您是否在其他地方设置了另一个焦点事件?
猜你喜欢
  • 1970-01-01
  • 2017-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多