【问题标题】:Detect click inside/outside of element with single event handler使用单个事件处理程序检测元素内部/外部的点击
【发布时间】:2011-06-07 08:00:36
【问题描述】:

假设我的页面中有一个 div。如何通过 JavaScript 或 JQuery 检测用户点击 div 内容或 div 内容之外的内容。请帮助小代码sn-p。 谢谢。

编辑:正如以下答案之一所述,我只想将事件处理程序附加到我的正文,并且还想知道单击了哪个元素。

【问题讨论】:

    标签: javascript jquery


    【解决方案1】:

    这是一个不需要 jquery 使用 Node.contains 的单行:

    // Get arbitrary element with id "my-element"
    var myElementToCheckIfClicksAreInsideOf = document.querySelector('#my-element');
    // Listen for click events on body
    document.body.addEventListener('click', function (event) {
        if (myElementToCheckIfClicksAreInsideOf.contains(event.target)) {
            console.log('clicked inside');
        } else {
            console.log('clicked outside');
        }
    });
    

    如果您想知道检查点击是否在元素本身上的边缘情况,Node.contains 会为元素本身返回 true(例如 element.contains(element) === true),因此这个 sn-p 应该始终有效。

    根据该 MDN 页面,浏览器支持似乎也涵盖了几乎所有内容。

    【讨论】:

      【解决方案2】:

      使用 jQuery:

      $(function() {
        $("body").click(function(e) {
          if (e.target.id == "myDiv" || $(e.target).parents("#myDiv").length) {
            alert("Inside div");
          } else {
            alert("Outside div");
          }
        });
      })
      #myDiv {
        background: #ff0000;
        width: 25vw;
        height: 25vh;
      }
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      <div id="myDiv"></div>

      【讨论】:

      • 这不会处理用户点击 div 的子元素的情况;它将报告"outside div"
      • 不错。您对parents() 的使用激发了我更新我的答案,以使用更多的 jQuery 和更少的老式遍历。
      • 如果 div 之外的元素使用 stopPropagation,这将不起作用,请参见此处的示例:jsfiddle.net/Flandre/YdrTA
      • 安德烈,我们对此无能为力,不是吗?
      • 喜欢$(e.target).parents("#myDiv").length,我记得,我发现的其他代码要复杂得多,甚至不能正常工作,非常感谢!
      【解决方案3】:

      使用 jQuery,并假设你有 &lt;div id="foo"&gt;:

      jQuery(function($){
        $('#foo').click(function(e){
          console.log( 'clicked on div' );
          e.stopPropagation(); // Prevent bubbling
        });
        $('body').click(function(e){
          console.log( 'clicked outside of div' );
        });
      });
      

      编辑:对于单个处理程序:

      jQuery(function($){
        $('body').click(function(e){
          var clickedOn = $(e.target);
          if (clickedOn.parents().andSelf().is('#foo')){
            console.log( "Clicked on", clickedOn[0], "inside the div" );
          }else{
            console.log( "Clicked outside the div" );
        });
      });
      

      【讨论】:

      • 感谢您的努力,但我希望以不同的方式。我想捕获发生单击的元素 id,并且我想在正文级别处理它不想使用 div 附加单击事件处理程序。
      • 如果我点击 #foo 也会触发正文处理程序,因为 foo 在正文中
      • @amosrivera 不,它不会,因为对stopPropagation 的调用会阻止它冒泡。你可以在这里自己测试一下:jsfiddle.net/Qh2MN
      • @Thomas 我已经用 body 上的一个处理程序更新了我的答案,告诉你点击是在 div 内部还是外部。
      • 您好,从 2021 年开始,.andSelf() 已被弃用。相反,只需将andSelf 替换为addBack,它应该可以正常工作。 api.jquery.com/andSelf
      【解决方案4】:

      与其使用 jQuery .parents 函数(如已接受的答案中所建议的那样),不如为此目的使用 .closest。正如explained in the jQuery api docs.closest 检查通过的元素及其所有父元素,而.parents 只检查父元素。 因此,这是可行的:

      $(function() {
          $("body").click(function(e) {
              if ($(e.target).closest("#myDiv").length) {
                  alert("Clicked inside #myDiv");
              } else { 
                  alert("Clicked outside #myDiv");
              }
          });
      })
      

      【讨论】:

        【解决方案5】:

        这个怎么样?

        <style type="text/css">
        div {border: 1px solid red; color: black; background-color: #9999DD;
        width: 20em; height: 40em;}
        </style>
        
        <script type="text/javascript">
        function sayLoc(e) {
          e = e || window.event;
          var tgt = e.target || e.srcElement;
        
          // Get top lef co-ords of div
          var divX = findPosX(tgt);
          var divY = findPosY(tgt);
        
          // Workout if page has been scrolled
          var pXo = getPXoffset();
          var pYo = getPYoffset();
        
          // Subtract div co-ords from event co-ords
          var clickX = e.clientX - divX + pXo;
          var clickY = e.clientY - divY + pYo;
        
          alert('Co-ords within div (x, y): ' + clickX + ', ' + clickY);
        }
        
        function findPosX(obj) {
          var curleft = 0;
          if (obj.offsetParent) {
            while (obj.offsetParent) {
              curleft += obj.offsetLeft;
              obj = obj.offsetParent;
            }
          } else if (obj.x) {
            curleft += obj.x;
          }
          return curleft;
        }
        
        function findPosY(obj) {
          var curtop = 0;
          if (obj.offsetParent) {
            while (obj.offsetParent) {
              curtop += obj.offsetTop;
              obj = obj.offsetParent;
            }
          } else if (obj.y) {
            curtop += obj.y;
          }
          return curtop;
        }
        
        function getPXoffset() {
          if (self.pageXOffset) {
            // all except Explorer
            return self.pageXOffset;
          } else if (
            document.documentElement &&
            document.documentElement.scrollTop
          ) {
            // Explorer 6 Strict
            return document.documentElement.scrollLeft;
          } else if (document.body) {
            // all other Explorers
            return document.body.scrollLeft;
          }
        }
        
        function getPYoffset() {
          if (self.pageYOffset) {
            // all except Explorer
            return self.pageYOffset;
          } else if (
            document.documentElement &&
            document.documentElement.scrollTop
          ) {
            // Explorer 6 Strict
            return document.documentElement.scrollTop;
          } else if (document.body) {
            // all other Explorers
            return document.body.scrollTop;
          }
        }
        
        </script>
        
        <div onclick="sayLoc(event);"></div>
        

        (来自http://bytes.com/topic/javascript/answers/151689-detect-click-inside-div-mozilla,使用谷歌。)

        【讨论】:

        • 对于现在可以在一行中完成的事情来说,这真是一大堆代码:stackoverflow.com/a/28432139/288906
        • 这正是我需要的,即使是疯狂的代码量
        • @fregante 此代码准确检测“内部几何”,而不是“内部分层”。
        【解决方案6】:

        这个问题可以用 X 和 Y 坐标回答,不用 JQuery:

               var isPointerEventInsideElement = function (event, element) {
                    var pos = {
                        x: event.targetTouches ? event.targetTouches[0].pageX : event.pageX,
                        y: event.targetTouches ? event.targetTouches[0].pageY : event.pageY
                    };
                    var rect = element.getBoundingClientRect();
                    return  pos.x < rect.right && pos.x > rect.left && pos.y < rect.bottom && pos.y > rect.top;
                };
        
                document.querySelector('#my-element').addEventListener('click', function (event) {
                   console.log(isPointerEventInsideElement(event, document.querySelector('#my-any-child-element')))
                });
        

        【讨论】:

          【解决方案7】:

          在原生 javaScript 中 - 在 ES6 中

          (() => {
              document.querySelector('.parent').addEventListener('click', event => {
                  alert(event.target.classList.contains('child') ? 'Child element.' : 'Parent element.');
              });
          })();
          .parent {
              display: inline-block;
              padding: 45px;
              background: lightgreen;
          }
          .child {
              width: 120px;
              height:60px;
              background: teal;
          }
          <div class="parent">
              <div class="child"></div>
          </div>

          【讨论】:

            【解决方案8】:

            对于 bootstrap 4,这对我有用。

            $(document).on('click', function(e) {
                $('[data-toggle="popover"],[data-original-title]').each(function() {
                    if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
                        $(this).popover('hide')
                    }
                });
            });
            

            jsfiddle 链接上的工作演示: https://jsfiddle.net/LabibMuhammadJamal/jys10nez/9/

            【讨论】:

              【解决方案9】:

              如果你想在 chrome 控制台中添加点击监听器,使用这个

              document.querySelectorAll("label")[6].parentElement.onclick = () => {console.log('label clicked');}
              

              【讨论】:

                【解决方案10】:

                您可以创建一个 z-index 为 100(选择一个数字)的窗帘,而不是使用主体,并为内部元素赋予更高的 z-index,而所有其他元素的 z-index 都比窗帘低。

                在此处查看工作示例:http://jsfiddle.net/Flandre/6JvFk/

                jQuery:

                $('#curtain').on("click", function(e) {
                
                    $(this).hide();
                    alert("clicked ouside of elements that stand out");
                
                });
                

                CSS:

                .aboveCurtain
                {
                    z-index: 200; /* has to have a higher index than the curtain */
                    position: relative;
                    background-color: pink;
                }
                
                #curtain
                {
                    position: fixed;
                    top: 0px;
                    left: 0px;
                    height: 100%;
                    background-color: black;
                    width: 100%;
                    z-index:100;   
                    opacity:0.5 /* change opacity to 0 to make it a true glass effect */
                }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-07-10
                  • 1970-01-01
                  • 2023-02-23
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多