使用纯JavaScript将点击事件附加到父亲身上

时间:2019-02-05 22:41:17

标签: javascript html

纯JS的新功能。

我正在创建必须与移动设备配合使用的菜单。

我正在尝试使用纯.js而不是使用jQuery进行创建,这是一个实验,并且充满挑战。

这是我的代码:

JS:

(function() {
  var menu = document.querySelector('.mobile-menu');
  var subMenu = {
    downToggle: document.getElementsByClassName('sub-menu'),
    downToggleTitle: document.getElementsByClassName('sub-menu-title'),
    subMenuItems: document.getElementsByClassName('sub-menu-item-mobile'),
    searchBar: document.getElementById('mobile-search'),
    onclickimg: document.querySelectorAll('.sub-menu-arrow'),
  };
  function listen() {
    for(var i=0; i<subMenu.downToggleTitle.length; i++) {
      subMenu.downToggleTitle.item(i).addEventListener('click', function(e) {

        // if there is a menu that's already open and it's not the element that's been clicked, close it before opening the selected menu
        for(var i=0; i<subMenu.downToggleTitle.length; i++) {
          if (subMenu.downToggleTitle.item(i).classList.contains('expanded') && subMenu.downToggleTitle.item(i) !== e.target) {
            subMenu.downToggleTitle.item(i).classList.toggle('expanded');
          }
        }

        // inside each sub-menu is a third-level-sub-menu. So inside each sub-menu we
        // check if it's already open, then close it
        for(var i=0; i<subMenu.subMenuItems.length; i++) {
          // console.log("test test")
          if(subMenu.subMenuItems.item(i).classList.contains('expanded') && subMenu.subMenuItems.item(i) !== e.target) {
            subMenu.subMenuItems.item(i).classList.toggle('expanded');
          }
        }
        this.classList.toggle('expanded');
      });
    }

    for(var i=0; i<subMenu.subMenuItems.length; i++) {
      subMenu.subMenuItems.item(i).addEventListener('click', function(e) {
        for(var i=0; i<subMenu.subMenuItems.length; i++) {
          if(subMenu.subMenuItems[i].classList.contains('expanded') && subMenu.subMenuItems[i] !== e.target) {
            subMenu.subMenuItems[i].classList.toggle('expanded');
            console.log("hello Aug 20");
          }
        }
        this.classList.toggle('expanded');
      });
    }
  } listen();
}());

我要更改的行为如下:

在第一个版本中,如果客户按下.sub-menu-title类的downToggleTitle类(变量li),则元素将切换类{{1} }。现在我想要一些不同的东西。

我在列表元素的末尾添加了expanded类,即变量sub-menu-arrowonclickimg上,所以如果客户单击箭头,所有类元素imgsub-menu-title)将切换类var = downToggleTitle

不会发生这种情况,因为如果出于某种原因,我以这种方式更改代码:

expanded

subMenu.onclickimg.item(i).addEventListener('click', function(e) { for(var i=0; i<subMenu.downToggleTitle.length; i++) { if (subMenu.downToggleTitle.item(i).classList.contains('expanded') && subMenu.downToggleTitle.item(i) !== e.target) { subMenu.downToggleTitle.item(i).classList.toggle('expanded'); } } 将切换到expanded元素(就像我说的,一些带有动画的图像)。

在这种情况下,关于如何定位父元素的任何建议?

还可以从点击事件中排除类别为sub-menu-arrow的锚元素吗?

mobile-toplevel-link元素是<a>类的其他子元素

2 个答案:

答案 0 :(得分:0)

如果要获取被单击目标的父元素,则可以利用当前的eventListener并使用e.target.parentNode来获取它。这将返回一个元素,您可以从中添加/删除CSS类,并可以完成几乎所有您喜欢的事情。请记住,您可以多次使用.parentNode,例如,如果要获取某个元素的“祖父母”(2级以上),可以编写e.target.parentNode.parentNode,依此类推。

答案 1 :(得分:0)

这实际上只是一条评论。您可以使用现代NodeList的迭代器功能极大地简化代码。我看不到 subMenu 对象的意义,它只是使引用更长。

此外,我替换了 getElementsByClassName ,因为它会生成一个活动的NodeList,而 querySelectorAll 返回一个静态列表。这里差别不大,但在其他情况下可能会很重要。

以下是一个简单的重构,它应该与您当前的代码应该完全一样。请注意,对于箭头功能, this 是从封闭的执行上下文中采用的。

(function() {
  let menu = document.querySelector('.mobile-menu');
  let downToggle = document.querySelectorAll('.sub-menu'),
    downToggleTitle = document.querySelectorAll('.sub-menu-title'),
    subMenuItems = document.querySelectorAll('.sub-menu-item-mobile'),
    searchBar = document.getElementById('mobile-search'),
    onclickimg = document.querySelectorAll('.sub-menu-arrow');

  function listen() {
    downToggleTitle.forEach(dtTitle => {
      dtTitle.addEventListener('click', function(e) {
        // If there is a menu that's already open
        // and it's not the element that's been clicked,
        // close it before opening the selected menu
        downToggleTitle.forEach(node => {
          if (node.classList.contains('expanded') && node !== this) {
            node.classList.toggle('expanded');
          }
        });

        // inside each sub-menu is a third-level-sub-menu. So inside each sub-menu
        // If it's already open, close it
        subMenuItems.forEach(item => {
          // console.log("test test")
          if (item.classList.contains('expanded') && item !== this) {
            item.classList.toggle('expanded');
          }
        });
        this.classList.toggle('expanded');
      });
    });

    subMenuItems.forEach(item => {
      item.addEventListener('click', function(e) {
        subMenuItems.forEach(item => {
          if (items.classList.contains('expanded') && item !== this) {
            item.classList.toggle('expanded');
            console.log("hello Aug 20");
          }
        });
        this.classList.toggle('expanded');
      });
    });
  }
  listen();
}());