【问题标题】:Toggle dropdown menu on li but prevent toggle clicking on ul在 li 上切换下拉菜单,但防止在 ul 上切换
【发布时间】:2019-03-22 00:11:42
【问题描述】:

在移动即时通讯上使用 javascript 来切换下拉菜单。 单击列表项时,下拉菜单应该可见,并且在第二次单击时切换回来。

问题:如果我喜欢在下拉菜单中使用搜索栏,下拉菜单会切换回搜索栏内的不可见点击。

jquery:

$('.has-dropdown-two').on('click', function() {

            $(this).toggleClass('is-active').children('ul').toggleClass('is-visible');  

  });

首先,我尝试创建一个 if 子句,例如:

if ($(this).hasClass('nav-dropdown-two') ) ..

不工作...然后我检查了console.log(this),它看起来像单击ul 它具有与单击li 时相同的输出。

我做了一个很简单的预览:

$('.has-dropdown-two').on('click', function() {
    var $this = $(this);

			
    		$(this).toggleClass('is-active').children('ul').toggleClass('is-visible');	
	
  });
.has-dropdown-two > .menu-link { display: inline-block; }

.has-dropdown-two.is-active > .nav-dropdown-two {
    display: block;
}

.nav-dropdown-two {
  display: none;
      position: absolute;

  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

	<li class="menu-item has-dropdown-two"> <a href="javascript:void(0);"  class="menu-link stopnewline">Search</a>
         	<ul class="nav-dropdown-two menu">
                <div class="search-container">
                    <form action="">
                      <input type="text"  name="search">
                      <button type="submit">search</button>
                    </form>
                  </div>                
     		</ul>
        </li>
	

根据lumio的解决方案编辑:

 $('.has-dropdown-two').on('click', function(event) {
    if ( event.target.tagName === 'A' || event.target.tagName === 'I' ) {
            $(this).toggleClass('is-active').children('ul').toggleClass('is-visible');
  }else{
    return;  
  }
  });

【问题讨论】:

  • 对您的问题进行一些澄清。点击UL确实会触发LI的点击,因为LI封装了UL。 LI 内部的一切都被认为是触发了 LI 的点击事件。暂时没时间找解决办法,如果以后还没有解决,我再研究一下。

标签: javascript jquery css


【解决方案1】:

确实如 mrdeadsven 所述。事件浮出水面。这意味着如果点击事件发生在孩子身上,它也会发生在父母身上。除非它被阻止。

您可以在 &lt;a&gt; 标记上设置点击处理程序,也可以通过将事件参数传递给事件处理程序函数来检查实际点击的内容。

$('.has-dropdown-two').on('click', function( event ) {
  // Check the tagName of clicked target element
  const tagName = event.target.tagName;
  if ( tagName === 'INPUT' || tagName === 'button' ) {
    return;
  }
  
  var $this = $(this);

  $(this).toggleClass('is-active').children('ul').toggleClass('is-visible');
});
.has-dropdown-two>.menu-link {
  display: inline-block;
}

.has-dropdown-two.is-active>.nav-dropdown-two {
  display: block;
}

.nav-dropdown-two {
  display: none;
  position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
  <li class="menu-item has-dropdown-two"> <a href="javascript:void(0);" class="menu-link stopnewline">Search</a>
    <ul class="nav-dropdown-two menu">
      <div class="search-container">
        <form action="">
          <input type="text" name="search">
          <button type="submit">search</button>
        </form>
      </div>
    </ul>
  </li>
</ul>

你可以很容易地完成上面的例子,而不需要使用 jQuery。


另一种解决方案是检查&lt;a&gt; 标签是否导致事件触发。这可能是更好的解决方案,因为它也适用于嵌套子菜单。

const subMenuToggle = ( event ) => {
  // Only watch clicks on .toggle-switch
  if ( !event.target.classList.contains( 'toggle-switch' ) ) {
    return;
  }

  // Prevent the actual click on the link
  event.preventDefault();
  
  // Toggle .is-active on parent <li> element
  const parent = event.target.parentNode;
  const className = 'is-active';
  parent.classList.toggle( className );
  
  // Only open the next direct ul
  parent.querySelectorAll( ':scope > ul' ).forEach( ( element ) =>
    element.classList.toggle( className )
  );
};

// Get all ul.navigation on the page
document
  .querySelectorAll( '.navigation' )
  .forEach( ( element ) => {
    element.addEventListener( 'click', subMenuToggle );
  } );
.nav-dropdown-two {
  display: none;
}

.nav-dropdown-two.is-active {
  display: block;
}
<!-- added .navigation for later -->
<ul class="navigation">
  <li class="menu-item has-dropdown-two">
    <!-- added the .toggle-switch for the event listener -->
    <a href="#" class="toggle-switch">Search</a>
    <ul class="nav-dropdown-two menu">
      <li>
        <div class="search-container">
          <form action="">
            <input type="text" name="search">
            <button type="submit">search</button>
          </form>
        </div>
      </li>
      <li>
        <a href="#" class="toggle-switch">more</a>
        <ul class="nav-dropdown-two">
          <li>Sub menu</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

【讨论】:

  • 这是一个很好的解决方案,除了一件事(这是一种拖累,但这是最坏的情况)。如果有嵌套的 LI 怎么办?例如,在表单中,他们启动了一个新的 LI,而您不希望嵌套的 LI 触发点击事件。您的标签系统无法解决这种情况。即使现在您拿走 FORM 并且他们按下按钮,搜索选项卡也将再次不可见,因为该按钮不在 tagName INPUT 中,因此它会触发点击事件。
  • @mrdeadsven .. 对,我忘了按钮。更新了我的答案并添加了一个示例,其中事件侦听器仅在由锚标记引起时才运行。
  • @mrdeadsven 正是我在第二部分导航中遇到的问题。感谢您指出。
  • 第二个版本通过向切换开关添加一个类&lt;a&gt; 标签来工作。您需要将toggle-switch 类添加到它才能工作
  • 我更新了代码,所以它显示了一个带有多层导航的示例
【解决方案2】:

就像@mrdeadsven 评论的那样,这是由于event propagation

您可以通过将另一个侦听器附加到您的表单并在其中调用 event.stopPropagation() 来关闭它。

$('form').on('click', function(e){
    e.stopPropagation();
})

【讨论】:

  • 很抱歉,但这不是一个好方法。尽管添加额外的事件侦听器只是为了停止传播是一种不好的做法,因为它会使事件循环变得混乱,最终变得相当混乱,难以调试。
猜你喜欢
  • 2017-06-16
  • 1970-01-01
  • 1970-01-01
  • 2013-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多