javascript 如何打开嵌套的HTML标记?

6pp0gazn  于 2023-05-05  发布在  Java
关注(0)|答案(2)|浏览(105)

我已经建立了一个offcnavas菜单与3个类别级别是嵌套在HTML标记。类别级别1打开类别级别2,类别级别2打开级别3。下面是代码片段:

const items = document.querySelectorAll('.navigation-offcanvas-list-item');

items.forEach(item => {
  item.addEventListener('click', event => {
    const containsIsOpen = item.classList.contains("is-open")

    if (!containsIsOpen) {
      item.classList.add("is-open")
    } else {
      item.classList.remove("is-open")
    }
  })
})
.third .navigation-offcanvas-list-item {
     overflow: hidden;
     transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
     max-height: 0;
     transform: scaleY(0);
     transform-origin: top;
}
 .second {
     overflow: hidden;
     transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
     max-height: 0;
     transform: scaleY(0);
     transform-origin: top;
}
 .second .navigation-offcanvas-list-item.is-open .third .navigation-offcanvas-list-item {
     max-height: none;
     transform: scaleY(1);
}
 .first .navigation-offcanvas-list-item.is-open .second {
     max-height: none;
     transform: scaleY(1);
}
<div class="navigation-offcanvas-container js-navigation-offcanvas">
  <div class="navigation-offcanvas-overlay-content">
    <!-- FIRST LEVEL -->
    <ul class="list-unstyled navigation-offcanvas-list">
      <li>
        <div class="first">
          <ul>
            <li class="navigation-offcanvas-list-item" data-first-trigger="id1" data-offcanvas-menu-level="level1">
              <div class="navigation-offcanvas-link nav-item">
                <span class="navigation-offcanvas-link-icon js-navigation-offcanvas-loading-icon">Category LEVEL1</span>
              </div>
              <div class="second" data-first-offcanvas="id1">
                <ul>
                  <li class="navigation-offcanvas-list-item" data-second-trigger="idd1" data-offcanvas-menu-level="level2">
                    <div class="navigation-offcanvas-link nav-item">
                      <span class="navigation-offcanvas-link-icon js-navigation-offcanvas-loading-icon">Category1 LEVEL2</span>
                    </div>
                    <div class="third" data-second-offcanvas="idd1">
                      <ul>
                        <li class="navigation-offcanvas-list-item">final link</li>
                        <li class="navigation-offcanvas-list-item">final link</li>
                        <li class="navigation-offcanvas-list-item">final link</li>
                      </ul>
                    </div>
                  </li>
                  <li class="navigation-offcanvas-list-item" data-second-trigger="idd2" data-offcanvas-menu-level="level2">
                    <div class="navigation-offcanvas-link nav-item">
                      <span class="navigation-offcanvas-link-icon js-navigation-offcanvas-loading-icon">Category2 LEVEL2</span>
                    </div>
                    <div class="third" data-second-offcanvas="idd2">
                      <ul>
                        <li class="navigation-offcanvas-list-item">final link</li>
                        <li class="navigation-offcanvas-list-item">final link</li>
                        <li class="navigation-offcanvas-list-item">final link</li>
                      </ul>
                    </div>
                  </li>
                </ul>
              </div>
            </li>
          </ul>
        </div>
      </li>
    </ul>
  </div>
</div>

现在的问题是,如果我打开第一个级别,类is-open被正确添加。level2也是如此。子菜单正确打开。
但现在我需要在单击第二级链接时关闭第二个子菜单,以及在单击第一级链接时关闭第一个子菜单。问题是(我猜,但我不确定),HTML标记是如此嵌套,以至于当我单击第二级链接打开第二个子菜单时,它将从整个标记中删除is-open。您可以在代码片段中看到该行为。
如何正确打开和关闭子菜单?

ql3eal8s

ql3eal8s1#

const items = document.querySelectorAll('.navigation-offcanvas-list-item');

items.forEach(item => {
  item.addEventListener('click', event => {
    let clickedElement = event.target;

    // eslint-disable-next-line no-cond-assign
    while (clickedElement && !clickedElement.classList.contains('navigation-offcanvas-list-item')) {
      clickedElement = clickedElement.parentNode;
    }

    if (clickedElement.classList.contains('navigation-offcanvas-list-item')) {
      let containsIsOpen = clickedElement.classList.contains("is-open");
      clickedElement.classList.toggle("is-open");

      if (containsIsOpen) {
        const nesteditems = clickedElement.querySelectorAll('.navigation-offcanvas-list-item.is-open');
        nesteditems.forEach(element => {
          element.classList.remove('is-open');
        });
      }
    }
  })
})

const secondItems = document.querySelectorAll('.second .navigation-offcanvas-list-item');

secondItems.forEach(item => {
  item.addEventListener('click', event => {
    const containsIsOpen = item.classList.contains("is-open")

    if (!containsIsOpen) {
      item.classList.add("is-open");
    } else {
      item.classList.remove("is-open");
    }
  })
})
.third .navigation-offcanvas-list-item {
     overflow: hidden;
     transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
     max-height: 0;
     transform: scaleY(0);
     transform-origin: top;
}
 .second {
     overflow: hidden;
     transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
     max-height: 0;
     transform: scaleY(0);
     transform-origin: top;
}
 .second .navigation-offcanvas-list-item.is-open .third .navigation-offcanvas-list-item {
     max-height: none;
     transform: scaleY(1);
}
 .first .navigation-offcanvas-list-item.is-open .second {
     max-height: none;
     transform: scaleY(1);
}
<div class="navigation-offcanvas-container js-navigation-offcanvas">
  <div class="navigation-offcanvas-overlay-content">
    <!-- FIRST LEVEL -->
    <ul class="list-unstyled navigation-offcanvas-list">
      <li>
        <div class="first">
          <ul>
            <li class="navigation-offcanvas-list-item" data-first-trigger="id1" data-offcanvas-menu-level="level1">
              <div class="navigation-offcanvas-link nav-item">
                <span class="navigation-offcanvas-link-icon js-navigation-offcanvas-loading-icon">Category LEVEL1</span>
              </div>
              <div class="second" data-first-offcanvas="id1">
                <ul>
                  <li class="navigation-offcanvas-list-item" data-second-trigger="idd1" data-offcanvas-menu-level="level2">
                    <div class="navigation-offcanvas-link nav-item">
                      <span class="navigation-offcanvas-link-icon js-navigation-offcanvas-loading-icon">Category1 LEVEL2</span>
                    </div>
                    <div class="third" data-second-offcanvas="idd1">
                      <ul>
                        <li class="navigation-offcanvas-list-item">final link</li>
                        <li class="navigation-offcanvas-list-item">final link</li>
                        <li class="navigation-offcanvas-list-item">final link</li>
                      </ul>
                    </div>
                  </li>
                  <li class="navigation-offcanvas-list-item" data-second-trigger="idd2" data-offcanvas-menu-level="level2">
                    <div class="navigation-offcanvas-link nav-item">
                      <span class="navigation-offcanvas-link-icon js-navigation-offcanvas-loading-icon">Category2 LEVEL2</span>
                    </div>
                    <div class="third" data-second-offcanvas="idd2">
                      <ul>
                        <li class="navigation-offcanvas-list-item">final link</li>
                        <li class="navigation-offcanvas-list-item">final link</li>
                        <li class="navigation-offcanvas-list-item">final link</li>
                      </ul>
                    </div>
                  </li>
                </ul>
              </div>
            </li>
          </ul>
        </div>
      </li>
    </ul>
  </div>
</div>
nfzehxib

nfzehxib2#

使用这个:

event.stopPropagation();

event.stopPropagation()

停止将事件冒泡到父元素,从而防止任何父处理程序收到相同事件的通知。

classList.toggle(classname,forcevalue)

从列表中移除现有类名并返回false。如果类名不存在,则添加它,函数返回true。
强制值,如果为真,则只添加。如果为false,则只删除值。

const items = document.querySelectorAll('.navigation-offcanvas-list-item.parent');
const items2 = document.querySelectorAll('.navigation-offcanvas-list-item.child');

items.forEach(item => {
  item.addEventListener('click', function(event){
        event.stopPropagation();// add this
        const nesteditems = document.querySelectorAll('.navigation-offcanvas-list-item.parent.is-open');
      nesteditems.forEach(element => {
        element.classList.toggle('is-open',element == event.target.closest('li'));
      });
    if(event.target.closest('li').classList.contains('parent')){
      item.classList.toggle("is-open")// use toogle
    }
  })
});
//for child
items2.forEach(item => {
  item.addEventListener('click', function(event){
        event.stopPropagation();// add this
        const nesteditems = document.querySelectorAll('.navigation-offcanvas-list-item.child.is-open');
      nesteditems.forEach(element => {
        element.classList.toggle('is-open',element == event.target.closest('li'));
      });
    if(event.target.closest('li').classList.contains('child')){
      item.classList.toggle("is-open")// use toogle
    }
    

  })
})
.third .navigation-offcanvas-list-item {
     overflow: hidden;
     transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
     max-height: 0;
     transform: scaleY(0);
     transform-origin: top;
}
 .second {
     overflow: hidden;
     transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
     max-height: 0;
     transform: scaleY(0);
     transform-origin: top;
}
 .second .navigation-offcanvas-list-item.is-open .third .navigation-offcanvas-list-item {
     max-height: none;
     transform: scaleY(1);
}
 .first .navigation-offcanvas-list-item.is-open .second {
     max-height: none;
     transform: scaleY(1);
}
<div class="navigation-offcanvas-container js-navigation-offcanvas">
  <div class="navigation-offcanvas-overlay-content">
    <!-- FIRST LEVEL -->
    <ul class="list-unstyled navigation-offcanvas-list">
      <li>
        <div class="first">
          <ul>
            <li class="navigation-offcanvas-list-item parent" data-first-trigger="id1" data-offcanvas-menu-level="level1">
              <div class="navigation-offcanvas-link nav-item">
                <span class="navigation-offcanvas-link-icon js-navigation-offcanvas-loading-icon">Category LEVEL1</span>
              </div>
              <div class="second" data-first-offcanvas="id1">
                <ul>
                  <li class="navigation-offcanvas-list-item child" data-second-trigger="idd1" data-offcanvas-menu-level="level2">
                    <div class="navigation-offcanvas-link nav-item">
                      <span class="navigation-offcanvas-link-icon js-navigation-offcanvas-loading-icon">Category1 LEVEL2</span>
                    </div>
                    <div class="third" data-second-offcanvas="idd1">
                      <ul>
                        <li class="navigation-offcanvas-list-item">final link</li>
                        <li class="navigation-offcanvas-list-item">final link</li>
                        <li class="navigation-offcanvas-list-item">final link</li>
                      </ul>
                    </div>
                  </li>
                  <li class="navigation-offcanvas-list-item child" data-second-trigger="idd2" data-offcanvas-menu-level="level2">
                    <div class="navigation-offcanvas-link nav-item">
                      <span class="navigation-offcanvas-link-icon js-navigation-offcanvas-loading-icon">Category2 LEVEL2</span>
                    </div>
                    <div class="third" data-second-offcanvas="idd2">
                      <ul>
                        <li class="navigation-offcanvas-list-item">final link</li>
                        <li class="navigation-offcanvas-list-item">final link</li>
                        <li class="navigation-offcanvas-list-item">final link</li>
                      </ul>
                    </div>
                  </li>
                </ul>
              </div>
            </li>
          </ul>
        </div>
      </li>
    </ul>
  </div>
</div>

相关问题