开发者

Detect click inside/outside of element with single event handler

Suppose I have one div in my page. how to detect the user click on div content or outside of div content through J开发者_如何学编程avaScript or JQuery. please help with small code snippet. thanks.

Edit: As commented in one of the answers below, I only want to attach an event handler to my body, and also want to know which element was clicked upon.


Here's a one liner that doesn't require jquery using 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');
    }
});

If you're wondering about the edge case of checking if the click is on the element itself, Node.contains returns true for the element itself (e.g. element.contains(element) === true) so this snippet should always work.

Browser support seems to cover pretty much everything according to that MDN page as well.


Using 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>


Using jQuery, and assuming that you have <div id="foo">:

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' );
  });
});

Edit: For a single handler:

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" );
  });
});


Rather than using the jQuery .parents function (as suggested in the accepted answer), it's better to use .closest for this purpose. As explained in the jQuery api docs, .closest checks the element passed and all its parents, whereas .parents just checks the parents. Consequently, this works:

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


What about this?

<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>

(from http://bytes.com/topic/javascript/answers/151689-detect-click-inside-div-mozilla, using the Google.)


This question can be answered with X and Y coordinates and without 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')))
        });


For bootstrap 4 this works for me.

$(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')
        }
    });
});

working demo on jsfiddle link: https://jsfiddle.net/LabibMuhammadJamal/jys10nez/9/


In vanilla javaScript - in 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>


If you want to add a click listener in chrome console, use this

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


function closePopover(sel) {
    $('body').on('click', function(e) {
        if (!$(event.target).closest(sel+', .popover-body').length) {
            $(sel).popover('hide');
        }
    });
}

closePopover('#elem1'); closePopover('#elem2');


Instead of using the body you could create a curtain with z-index of 100 (to pick a number) and give the inside element a higher z-index while all other elements have a lower z-index than the curtain.

See working example here: 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 */
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜