首页 > 解决方案 > 带有后退按钮的 jquery 多级菜单 - 正在创建多个后退按钮元素

问题描述

我正在开发移动菜单交互

它应该如何工作:

单击“打开”时,会显示一个带有两个 li 项目的 ul 元素。当单击任一 li 项目时,会显示一个嵌套的 ul,如果其中的任何 li 项目有子项,则标记中还包含一个显示“更多”的跨度。

当我单击“更多”时,我看到带有 li 项目的第三级 ul,并且使用 jquery 创建了一个后退按钮并附加到第三级菜单。

问题

当我单击第一个父 li 时,我得到了预期的结果。当我单击另一个父 li 及其子项然后“返回”时,我看到正在创建多个“返回”元素。

我无法解释为什么。我的逻辑可能存在缺陷,我希望有人能帮助我发现它。或者建议一种更好地调试它的方法。

提前致谢。如果需要,我可以详细说明

小提琴https ://jsfiddle.net/left23/ktdsxk1d/

var toggle_expand = $('.toggle-expand');
var menu = $('#main-nav');
var expand_menu = $('.expand-sub');
var sub_menu = $('.main-menu--sub');
var first_level_item = $('#main-nav > .main-menu > li');
var second_level_menu = $('#main-nav > .main-menu > li > .main-menu--sub-1');
var second_level_item = $('#main-nav > .main-menu > li > .main-menu > li');
var third_level_menu = $('.main-menu--sub-2');

// Mobile Menu Show/Hide.
toggle_expand.on('click', function(e) {
  $(this).toggleClass('toggle-expand--open');
  menu.toggleClass('main-nav--open');

  if (!$(this).hasClass('toggle-expand--open')) {
    reset();
  }

});

// top level menu items

first_level_item.on('click', function(e) {

  first_level_item.not(this).each(function() {
    $(this).removeClass('active');
    $(this).children(second_level_menu).removeClass('main-menu--sub-open');
  });

  $(this).toggleClass('active');
  $(this).children('.main-menu--sub').toggleClass('main-menu--sub-open');

  expandMenu();

});


// second level menu items
function expandMenu() {

  expand_menu.on('click', function(e) {

    $(this).addClass('expand-sub--open');
    $(this).next(third_level_menu).addClass('main-menu--sub-open');
    $(this).closest(first_level_item).addClass('active');

    e.stopPropagation();

    backButton();

  });

}

// back button
function backButton() {

  var back_button_html = '<div class="back-button">Back</div>';

  // append element to bottom of list
  third_level_menu.append(back_button_html);

  var back_button = $('.back-button');

  back_button.on('click', function(e) {

    console.log('back');

    $(this).parent(third_level_menu).removeClass('main-menu--sub-open');
    $(this).parent(third_level_menu).prev(expand_menu).removeClass('expand-sub--open');

    $(this).parents('#main-nav > .main-menu > li').addClass('active');

    back_button.remove();

    e.stopPropagation();

  });

}


// reset to starting state
function reset() {
  console.log('reset');
  first_level_item.removeClass('active');
  sub_menu.removeClass('main-menu--sub-open');
  expand_menu.removeClass('expand-sub--open');
  $('.back-button').remove();
}

标签: jquery

解决方案


这个问题的主要原因是因为您third_level_menu同时创建了两个按钮并绑定了两个按钮click()事件。所以如果我们点击一​​个more按钮并切换到另一个按钮并再次first_level_item点击more按钮,那么它会不断地创建back按钮并将一个click事件绑定到所有back按钮,包括那些已经绑定了click事件的按钮。

当我们在 之间切换时first_level_item,会expandMenu()遇到与我上面提到的相同的问题。

因此,在绑定click()事件之前,我们可以off()使用原始事件来避免多次触发相同的事件。back另外,选择要删除的右侧按钮。

$('.back-button:visible');

third_level_menu附加新back按钮的权利。

$('.main-menu--sub-2:visible');

var toggle_expand = $('.toggle-expand');
var menu = $('#main-nav');
var expand_menu = $('.expand-sub');
var sub_menu = $('.main-menu--sub');
var first_level_item = $('#main-nav > .main-menu > li');
var second_level_menu = $('#main-nav > .main-menu > li > .main-menu--sub-1');
var second_level_item = $('#main-nav > .main-menu > li > .main-menu > li');
var third_level_menu = $('.main-menu--sub-2');

// Mobile Menu Show/Hide.
toggle_expand.on('click', function(e) {
  $(this).toggleClass('toggle-expand--open');
  menu.toggleClass('main-nav--open');

  if (!$(this).hasClass('toggle-expand--open')) {
    reset();
  }

});

// top level menu items

first_level_item.on('click', function(e) {

  first_level_item.not(this).each(function() {
    $(this).removeClass('active');
    $(this).children(second_level_menu).removeClass('main-menu--sub-open');
  });

  $(this).toggleClass('active');
  $(this).children('.main-menu--sub').toggleClass('main-menu--sub-open');

  expandMenu();

});


// second level menu items
function expandMenu() {

  expand_menu.off('click').on('click', function(e) {

    $(this).addClass('expand-sub--open');
    $(this).next(third_level_menu).addClass('main-menu--sub-open');
    $(this).closest(first_level_item).addClass('active');

    e.stopPropagation();

    backButton();

  });

}

// back button
function backButton() {

  var back_button_html = '<div class="back-button">Back</div>';

  // append element to bottom of list
  $('.main-menu--sub-2:visible').append(back_button_html);

  var back_button = $('.back-button:visible');

  back_button.on('click', function(e) {

    console.log('back');

    $(this).parent(third_level_menu).removeClass('main-menu--sub-open');
    $(this).parent(third_level_menu).prev(expand_menu).removeClass('expand-sub--open');

    $(this).parents('#main-nav > .main-menu > li').addClass('active');

    $(this).remove();
    
    e.stopPropagation();
  });

}


// reset to starting state
function reset() {
  console.log('reset');
  first_level_item.removeClass('active');
  // not sure if we want this! Consider a starting state
  sub_menu.removeClass('main-menu--sub-open');
  expand_menu.removeClass('expand-sub--open');
  $('.back-button').remove();
}
.main-nav {
  display: none;
  width: 90%;
}

.main-nav--open {
  display: block;
}

.main-nav {
  z-index: 99;
}

.main-nav>ul.main-menu {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: flex-start;
  padding: 0 1rem;
}

.main-nav>ul.main-menu>li.main-menu__item {
  flex: 0 1 33%;
  position: relative;
  display: flex;
  justify-content: space-around;
  align-content: flex-start;
  background: red;
  margin-right: 1rem;
}

.main-nav>ul.main-menu>li.main-menu__item>a {
  display: block;
  padding: 1rem;
  text-align: center;
  color: white;
  font-weight: 700;
  text-transform: uppercase;
  text-decoration: none;
  transition: padding 0.2s;
}

.main-nav>ul.main-menu>li.main-menu__item.active>a {
  padding: 2rem 1rem;
}

.main-nav>ul.main-menu>li.main-menu__item.active>.main-menu--sub-open {
  z-index: 20;
}

.main-nav>ul.main-menu>li.main-menu__item>ul.main-menu.main-menu--sub.main-menu--sub-1 {
  display: none;
  position: fixed;
  background: rgba(0, 0, 0, 0.6);
  padding: 1rem 1rem 0;
  width: 50vw;
  top: 160px;
  left: 0;
  bottom: 0;
}

.main-nav>ul.main-menu>li.main-menu__item>ul.main-menu.main-menu--sub.main-menu--sub-1.main-menu--sub-open {
  display: block;
}

.main-nav>ul.main-menu>li.main-menu__item>ul.main-menu.main-menu--sub.main-menu--sub-1>li.main-menu__item.main-menu__item--with-sub.main-menu__item--sub.main-menu__item--sub-1 {
  border-top: 1px solid white;
  display: flex;
  justify-content: space-between;
}

.main-nav>ul.main-menu>li.main-menu__item>ul.main-menu.main-menu--sub.main-menu--sub-1>li.main-menu__item.main-menu__item--with-sub.main-menu__item--sub.main-menu__item--sub-1:first-child {
  border: 0 none;
}

.main-nav>ul.main-menu>li.main-menu__item>ul.main-menu.main-menu--sub.main-menu--sub-1>li.main-menu__item.main-menu__item--with-sub.main-menu__item--sub.main-menu__item--sub-1>a {
  display: block;
  padding: 1rem 0;
  color: white;
  font-weight: 700;
  text-transform: uppercase;
  text-decoration: none;
}

.main-nav>ul.main-menu>li.main-menu__item>ul.main-menu.main-menu--sub.main-menu--sub-1>li.main-menu__item.main-menu__item--with-sub.main-menu__item--sub.main-menu__item--sub-1>ul.main-menu.main-menu--sub.main-menu--sub-1.main-menu--sub-2 {
  display: none;
  position: fixed;
  background: rgba(0, 0, 0, 1);
  padding: 1rem 1rem 0;
  width: 50vw;
  top: 160px;
  left: 0;
  bottom: 0;
  z-index: 5;
}

.main-nav>ul.main-menu>li.main-menu__item>ul.main-menu.main-menu--sub.main-menu--sub-1>li.main-menu__item.main-menu__item--with-sub.main-menu__item--sub.main-menu__item--sub-1>ul.main-menu.main-menu--sub.main-menu--sub-1.main-menu--sub-2.main-menu--sub-open {
  display: block;
}

.main-nav>ul.main-menu>li.main-menu__item>ul.main-menu.main-menu--sub.main-menu--sub-1>li.main-menu__item.main-menu__item--with-sub.main-menu__item--sub.main-menu__item--sub-1>ul.main-menu.main-menu--sub.main-menu--sub-1.main-menu--sub-2>li.main-menu__item.main-menu__item--with-sub.main-menu__item--sub.main-menu__item--sub-1.main-menu__item--sub-2 {
  border-top: 1px solid white;
  display: flex;
  justify-content: space-between;
}

.main-nav>ul.main-menu>li.main-menu__item>ul.main-menu.main-menu--sub.main-menu--sub-1>li.main-menu__item.main-menu__item--with-sub.main-menu__item--sub.main-menu__item--sub-1>ul.main-menu.main-menu--sub.main-menu--sub-1.main-menu--sub-2>li.main-menu__item.main-menu__item--with-sub.main-menu__item--sub.main-menu__item--sub-1.main-menu__item--sub-2:first-child {
  border: 0 none;
}

.main-nav>ul.main-menu>li.main-menu__item>ul.main-menu.main-menu--sub.main-menu--sub-1>li.main-menu__item.main-menu__item--with-sub.main-menu__item--sub.main-menu__item--sub-1>ul.main-menu.main-menu--sub.main-menu--sub-1.main-menu--sub-2>li.main-menu__item.main-menu__item--with-sub.main-menu__item--sub.main-menu__item--sub-1.main-menu__item--sub-2>a {
  display: block;
  padding: 1rem 0;
  color: white;
  font-weight: 700;
  text-transform: uppercase;
  text-decoration: none;
}

.toggle-expand {
  display: inline-block;
  text-align: right;
  padding: 1rem;
  text-decoration: none;
}

.toggle-expand--open {
  background-color: white;
}

.toggle-expand__open {
  display: inline-block;
  text-align: center;
}

.toggle-expand--open .toggle-expand__open {
  display: none;
}

.toggle-expand__close {
  display: none;
  text-align: center;
}

.toggle-expand--open .toggle-expand__close {
  display: inline-block;
}

.back-button {
  cursor: pointer;
  display: inline-block;
  height: 2rem;
  width: auto;
  color: white;
  position: absolute;
  right: 1rem;
  padding: 1rem;
  background: red;
}

.expand-sub {
  cursor: pointer;
  display: inline-block;
  height: 2rem;
  width: auto;
  color: black;
  position: absolute;
  right: 1rem;
  padding: 1rem;
  background: rgba(255, 255, 255, 0.4);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<a href="#" id="toggle-expand" class="toggle-expand toggle-expand--open">
  <span class="toggle-expand__open">
    Close
    </span>
  <span class="toggle-expand__close">Click to open menu</span>
</a>

<nav id="main-nav" class="main-nav">
  <ul class="main-menu">
    <li class="main-menu__item main-menu__item--with-sub">
      <a class="main-menu__link main-menu__link--with-sub" href="#">
      Item 1
    </a>
      <ul class="main-menu main-menu--sub main-menu--sub-1">
        <li class="main-menu__item main-menu__item--with-sub main-menu__item--sub main-menu__item--sub-1 main-menu__item--with-sub">
          <a class="main-menu__link main-menu__link--with-sub main-menu__link--sub main-menu__link--sub-1 main-menu__link--with-sub" href="#">
      Item 1 Child 1</a>
          <span class="expand-sub">more</span>
          <ul class="main-menu main-menu--sub main-menu--sub-1 main-menu--sub main-menu--sub-2">
            <li class="main-menu__item main-menu__item--with-sub main-menu__item--sub main-menu__item--sub-1 main-menu__item--with-sub main-menu__item--sub main-menu__item--sub-2">
              <a class="main-menu__link main-menu__link--with-sub main-menu__link--sub main-menu__link--sub-1 main-menu__link--with-sub main-menu__link--sub main-menu__link--sub-2" href="#">Item 1 Child 1 Grandchild 1</a>
            </li>
            <li class="main-menu__item main-menu__item--with-sub main-menu__item--sub main-menu__item--sub-1 main-menu__item--with-sub main-menu__item--sub main-menu__item--sub-2">
              <a class="main-menu__link main-menu__link--with-sub main-menu__link--sub main-menu__link--sub-1 main-menu__link--with-sub main-menu__link--sub main-menu__link--sub-2" href="#">Item 1 Child 1 Grandchild 2</a>
            </li>
          </ul>
        </li>
      </ul>
    </li>

    <li class="main-menu__item main-menu__item--with-sub">
      <a class="main-menu__link main-menu__link--with-sub" href="#">
      Item 2
    </a>
      <ul class="main-menu main-menu--sub main-menu--sub-1">
        <li class="main-menu__item main-menu__item--with-sub main-menu__item--sub main-menu__item--sub-1 main-menu__item--with-sub">
          <a class="main-menu__link main-menu__link--with-sub main-menu__link--sub main-menu__link--sub-1 main-menu__link--with-sub" href="#">
      Item 2 Child 1</a>
          <span class="expand-sub">more</span>
          <ul class="main-menu main-menu--sub main-menu--sub-1 main-menu--sub main-menu--sub-2">
            <li class="main-menu__item main-menu__item--with-sub main-menu__item--sub main-menu__item--sub-1 main-menu__item--with-sub main-menu__item--sub main-menu__item--sub-2">
              <a class="main-menu__link main-menu__link--with-sub main-menu__link--sub main-menu__link--sub-1 main-menu__link--with-sub main-menu__link--sub main-menu__link--sub-2" href="#">Item 2 Child 1 Grandchild 1</a>
            </li>
            <li class="main-menu__item main-menu__item--with-sub main-menu__item--sub main-menu__item--sub-1 main-menu__item--with-sub main-menu__item--sub main-menu__item--sub-2">
              <a class="main-menu__link main-menu__link--with-sub main-menu__link--sub main-menu__link--sub-1 main-menu__link--with-sub main-menu__link--sub main-menu__link--sub-2" href="#">Item 2 Child 1 Grandchild 2</a>
            </li>
          </ul>
        </li>
      </ul>
    </li>





  </ul>


</nav>


推荐阅读