【问题标题】:How do I prevent a parent's onclick event from firing when a child anchor is clicked?单击子锚点时,如何防止触发父级的 onclick 事件?
【发布时间】:2010-11-25 00:54:46
【问题描述】:

我目前正在使用 jQuery 来制作可点击的 div,并且在这个 div 中我也有锚点。我遇到的问题是,当我点击一个锚点时,两个点击事件都在触发(对于 div 和锚点)。单击锚点时如何防止 div 的 onclick 事件触发?

这是损坏的代码:

JavaScript

var url = $("#clickable a").attr("href");

$("#clickable").click(function() {
    window.location = url;
    return true;
})

HTML

<div id="clickable">
    <!-- Other content. -->
    <a href="http://foo.com">I don't want #clickable to handle this click event.</a>
</div>

【问题讨论】:

    标签: javascript jquery event-propagation


    【解决方案1】:

    使用stopPropagation方法,看一个例子:

    $("#clickable a").click(function(e) {
       e.stopPropagation();
    });
    

    正如 jQuery Docs 所说:

    stopPropagation 方法防止事件冒泡 DOM 树,防止任何父处理程序收到事件通知。

    请记住,它不会阻止其他侦听器处理此事件(例如,一个按钮的多次单击处理程序),如果不是您想要的效果,您必须使用@987654324 @ 代替。

    【讨论】:

    • 小心,以免意外将事件侦听器设置为被动
    【解决方案2】:
    <a onclick="return false;" href="http://foo.com">I want to ignore my parent's onclick event.</a>
    

    【讨论】:

    • 这也会阻止链接导航。
    • 是的,还是不需要什么?还是需要nevegar?
    【解决方案3】:

    事件冒泡到 DOM 中附加点击事件的最高点。因此,在您的示例中,即使您在 div 中没有任何其他可显式单击的元素,div 的每个子元素也会将其单击事件冒泡到 DOM 中,直到 DIV 的单击事件处理程序捕获它。

    对此有两种解决方案,即检查事件的真正发起者。 jQuery 将 eventargs 对象与事件一起传递:

    $("#clickable").click(function(e) {
        var senderElement = e.target;
        // Check if sender is the <div> element e.g.
        // if($(e.target).is("div")) {
        window.location = url;
        return true;
    });
    

    您还可以将点击事件处理程序附加到您的链接,在他们自己的处理程序执行后告诉他们stop event bubbling

    $("#clickable a").click(function(e) {
       // Do something
       e.stopPropagation();
    });
    

    【讨论】:

    • 很好的答案。很高兴知道也有选择。
    • +1!使用 stopPropagation 附加点击处理程序是一个非常好的技巧,谢谢!
    • 如果你有一堆想要阻止传播的元素,你可以找到它们的父元素并 head 防止它在那里冒泡。因此,与其拦截 div 中的所有 a 链接,不如说 - 甚至拦截 div 本身的点击并阻止它变得更高,然后您就可以设置了。
    • 在父级中使用if( e.target !== this) return; 比在子级中使用e.stopPropagation() 更好,因为您永远不知道其他人是否将某些处理程序附加到子级,或者库是否必须将处理程序附加到子级(并且您不想弄乱库代码)。这是一个更好的关注点分离。
    • if( e.target !== this) return; 签入父项意味着如果单击该父项中没有自己的 onClick 处理程序的任何其他子项,则不会发生任何事情。所以它对于你有例如的情况是没有用的。一个可点击的父 div。 e.stopPropagation() 工作正常。
    【解决方案4】:

    添加a如下:

    <a href="http://foo.com" onclick="return false;">....</a>
    

    return false; 来自#clickable 的点击处理程序,例如:

      $("#clickable").click(function() {
            var url = $("#clickable a").attr("href");
            window.location = url;
            return false;
       });
    

    【讨论】:

      【解决方案5】:

      您需要阻止事件到达(冒泡到)父级(div)。 请参阅有关冒泡的部分here,以及特定于 jQuery 的 API 信息here

      【讨论】:

      • 酷。感谢您提供有关事件冒泡的信息。
      【解决方案6】:

      所有的解决方案都是复杂的 jscript。这是最简单的版本:

      var IsChildWindow=false;
      
      function ParentClick()
      {
          if(IsChildWindow==true)
          {
              IsChildWindow==false;
              return;
          }
          //do ur work here   
      }
      
      
      function ChildClick()
      {
          IsChildWindow=true;
          //Do ur work here    
      }
      

      【讨论】:

      • 我认为您在“IsChildWindow==false;”行中犯了一个错误- 不应该是“IsChildWindow = false;”吗?
      【解决方案7】:

      如果您在可点击的 div 中有多个元素,您应该这样做:

      $('#clickable *').click(function(e){ e.stopPropagation(); });
      

      【讨论】:

        【解决方案8】:

        要将某些子元素指定为不可点击,请编写 css 层次结构,如下例所示。

        在这个例子中,我停止传播到类“.subtable”的表内的 td 内 tr 内的任何元素 (*)

        $(document).ready(function()
        {    
           $(".subtable tr td *").click(function (event)
           {
               event.stopPropagation();
           });
        
        });
        

        【讨论】:

          【解决方案9】:

          这里是我为寻找非 jQuery 代码(纯 javascript)的每个人提供的解决方案

          document.getElementById("clickable").addEventListener("click", function( e ){
              e = window.event || e; 
              if(this === e.target) {
                  // put your code here
              }
          });
          

          如果点击父母的孩子,您的代码将不会被执行

          【讨论】:

          • 这对我有用,我需要一个非 JS/jQuery 解决方案。 10 倍!
          • 很好的答案。我只是直接通过了事件。所以我没有使用 window.event,这是 MDN 不鼓励的:developer.mozilla.org/en-US/docs/Web/API/Window/event。如果您能抽出时间,如果您能评论一下您为什么使用window.event,我将不胜感激(也许这是 2015 年存在的问题,或者我无法理解原因)。
          【解决方案10】:

          使用return false;e.stopPropogation(); 将不允许执行更多代码。它会在此时自行停止流动。

          【讨论】:

          • 是的,这很重要——我自己也遇到过。但是上面来自 Rex 的答案很有帮助 - 可以获得被点击的元素,并且在某些情况下,在您试图停止的逻辑中使用它。 .target.nodeName 也有助于清楚地了解被击中的内容。
          【解决方案11】:

          你也可以试试这个

          $("#clickable").click(function(event) {
             var senderElementName = event.target.tagName.toLowerCase();
             if(senderElementName === 'div')
             {
                 // do something here 
             } 
             else
             {
                //do something with <a> tag
             }
          });
          

          【讨论】:

            【解决方案12】:

            如果有人需要就写(为我工作):

            event.stopImmediatePropagation()
            

            来自this 解决方案。

            【讨论】:

              【解决方案13】:

              如果您在任何情况下都不打算与内部元素交互,那么 CSS 解决方案可能对您有用。

              只需将内部元素设置为pointer-events: none

              在你的情况下:

              .clickable > a {
                  pointer-events: none;
              }
              

              或一般针对所有内部元素:

              .clickable * {
                  pointer-events: none;
              }
              

              这个简单的 hack 为我在使用 ReactJS 开发时节省了大量时间

              浏览器支持可以在这里找到:http://caniuse.com/#feat=pointer-events

              【讨论】:

                【解决方案14】:

                这是一个使用 Angular 2+ 的示例

                例如,如果您想在用户单击模态组件外部时关闭它:

                // Close the modal if the document is clicked.
                
                @HostListener('document:click', ['$event'])
                public onDocumentClick(event: MouseEvent): void {
                  this.closeModal();
                }
                
                // Don't close the modal if the modal itself is clicked.
                
                @HostListener('click', ['$event'])
                public onClick(event: MouseEvent): void {
                  event.stopPropagation();
                }
                

                【讨论】:

                  【解决方案15】:

                  如果有人在使用 React 时遇到这个问题,我就是这样解决的。

                  scss:

                  #loginBackdrop {
                  position: absolute;
                  width: 100% !important;
                  height: 100% !important;
                  top:0px;
                  left:0px;
                  z-index: 9; }
                  
                  #loginFrame {
                  width: $iFrameWidth;
                  height: $iFrameHeight;
                  background-color: $mainColor;
                  position: fixed;
                  z-index: 10;
                  top: 50%;
                  left: 50%;
                  margin-top: calc(-1 * #{$iFrameHeight} / 2);
                  margin-left: calc(-1 * #{$iFrameWidth} / 2);
                  border: solid 1px grey;
                  border-radius: 20px;
                  box-shadow: 0px 0px 90px #545454; }
                  

                  组件的 render():

                  render() {
                      ...
                      return (
                          <div id='loginBackdrop' onClick={this.props.closeLogin}>
                              <div id='loginFrame' onClick={(e)=>{e.preventDefault();e.stopPropagation()}}>
                               ... [modal content] ...
                              </div>
                          </div>
                      )
                  }
                  

                  通过为子模态(内容 div)添加 onClick 函数,防止鼠标点击事件到达父元素的 'closeLogin' 函数。

                  这对我有用,我能够使用 2 个简单的 div 创建模态效果。

                  【讨论】:

                    【解决方案16】:

                    var inner = document.querySelector("#inner");
                    var outer = document.querySelector("#outer");
                    inner.addEventListener('click',innerFunction);
                    outer.addEventListener('click',outerFunction);
                    
                    function innerFunction(event){
                      event.stopPropagation();
                      console.log("Inner Functiuon");
                    }
                    
                    function outerFunction(event){
                      console.log("Outer Functiuon");
                    }
                    <!DOCTYPE html>
                    <html>
                    <head>
                      <meta charset="utf-8">
                      <meta name="viewport" content="width=device-width">
                      <title>Pramod Kharade-Event with Outer and Inner Progration</title>
                    </head>
                    <body>
                    <div id="outer" style="width:100px;height:100px;background-color:green;">
                      <div id="inner" style="width:35px;height:35px;background-color:yellow;"></div>
                    </div>
                    </body>
                    </html>

                    【讨论】:

                      【解决方案17】:

                      ignoreParent() 是纯 JavaScript 解决方案。

                      它作为一个中间层,将鼠标点击的坐标与子元素的坐标进行比较。两个简单的实现步骤:

                      1. 将 ignoreParent() 代码放在您的页面上。

                      2. 代替父母原来的onclick="parentEvent();",写:

                      onclick="ignoreParent(['parentEvent()', 'child-ID']);"
                      

                      您可以将任意数量的子元素的 ID 传递给函数,并排除其他元素。

                      如果您单击其中一个子元素,则不会触发父事件。如果您单击了父元素,但没有单击任何子元素 [作为参数提供],则会触发父事件。

                      ignoreParent() code on Github

                      【讨论】:

                        【解决方案18】:

                        内联替代:

                        <div>
                            <!-- Other content. -->
                            <a onclick='event.stopPropagation();' href="http://foo.com">I don't want #clickable to handle this click event.</a>
                        </div>
                        

                        【讨论】:

                          【解决方案19】:

                          如果它是在内联上下文中,在 HTML 中试试这个:

                          onclick="functionCall();event.stopPropagation();
                          

                          【讨论】:

                            【解决方案20】:

                            e.stopPropagation() 是一个正确的解决方案,但如果您不想将任何事件处理程序附加到您的内部锚点,您可以简单地将这个处理程序附加到您的外部 div:

                            e => { e.target === e.currentTarget && window.location = URL; }
                            

                            【讨论】:

                              【解决方案21】:

                              您可以检查目标是否不是您的 div 元素,然后在父级上发出另一个单击事件,之后您将从句柄“返回”。

                              $('clickable').click(function (event) {
                                  let div = $(event.target);
                                  if (! div.is('div')) {
                                     div.parent().click();
                                     return;
                                  }
                                  // Then Implement your logic here
                              }
                              

                              【讨论】:

                                【解决方案22】:

                                如果单击子元素,则事件会冒泡到父元素和 event.target !== event.currentTarget。

                                所以在你的函数中,你可以检查这个并提前返回,即:

                                var url = $("#clickable a").attr("href");
                                $("#clickable").click(function(event) {
                                    if ( event.target !== event.currentTarget ){
                                        // user clicked on a child and we ignore that
                                        return;
                                    }
                                    window.location = url;
                                    return true;
                                })
                                

                                【讨论】:

                                  【解决方案23】:

                                  这是一个对我有用的非 jQuery 解决方案。

                                  <div style="background:cyan; width:100px; height:100px;" onclick="if (event.srcElement==this) {console.log('outer');}">
                                      <a style="background:red" onclick="console.log('inner');">Click me</a>
                                  </div>

                                  【讨论】:

                                    【解决方案24】:

                                    this 不可用时(React 等),我与ev.currentTarget 进行比较。

                                    $("#clickable").click(function(e) {
                                        if (e.target === e.currentTarget) {
                                            window.location = url;
                                            return true;
                                        }
                                    })
                                    

                                    【讨论】:

                                      【解决方案25】:

                                      这就是你要找的东西

                                      mousedown 事件。这适用于每个 DOM 元素,以防止像这样的 javascript 焦点处理程序:

                                      $('.no-focus').mousedown(function (e) {
                                         e.prevenDefault()
                                      
                                         // do stuff
                                      }
                                      

                                      vue.js框架中,你可以像这样使用修饰符:

                                      <span @mousedown.prevent> no focus </span>
                                      

                                      请注意,在输入上使用会阻止文本选择处理程序

                                      【讨论】:

                                        猜你喜欢
                                        • 2023-01-22
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 2010-11-02
                                        • 1970-01-01
                                        相关资源
                                        最近更新 更多