Обнаружение внешнего элемента щелчка (ванильный JavaScript)


Я искал хорошее решение везде, но я не могу найти тот, который делает Не использовать jQuery.

есть ли кросс-браузер, обычный способ (без странных хаков или легко взломать код), чтобы обнаружить щелчок за пределами элемента (который может или не может иметь детей)?

4 52

4 ответа:

добавить прослушиватель событий к document и использовать Node.contains() чтобы узнать, находится ли цель события (который является самым внутренним щелчком элемента) внутри указанного элемента. Он работает даже в IE5

var specifiedElement = document.getElementById('a');

//I'm using "click" but it works with any event
document.addEventListener('click', function(event) {
  var isClickInside = specifiedElement.contains(event.target);

  if (!isClickInside) {
    //the click was outside the specifiedElement, do something
  }
});

var specifiedElement = document.getElementById('a');

//I'm using "click" but it works with any event
document.addEventListener('click', function(event) {
  var isClickInside = specifiedElement.contains(event.target);
  if (isClickInside) {
    alert('You clicked inside A')
  } else {
    alert('You clicked outside A')
  }
});
div {
  margin: auto;
  padding: 1em;
  max-width: 6em;
  background: rgba(0, 0, 0, .2);
  text-align: center;
}
Is the click inside A or outside?
<div id="a">A
  <div id="b">B
    <div id="c">C</div>
  </div>
</div>

вам нужно обработать событие щелчка на уровне документа. В объекте события, у вас есть target свойство, самый внутренний элемент DOM, который был нажат. При этом вы проверяете себя и поднимаете своих родителей до элемента документа, если один из них является вашим наблюдаемым элементом.

пример jsFiddle

document.addEventListener("click", function (e) {
  var level = 0;
  for (var element = e.target; element; element = element.parentNode) {
    if (element.id === 'x') {
      document.getElementById("out").innerHTML = (level ? "inner " : "") + "x clicked";
      return;
    }
    level++;
  }
  document.getElementById("out").innerHTML = "not x clicked";
});

как всегда, это не кросс-плохой браузер совместим из-за addEventListener / attachEvent, но он работает как этот.

ребенок щелкнул, когда не событие.цель, но один из ее родителей-это наблюдаемый элемент (я просто считаю уровень для этого). У вас также может быть логический var, если элемент найден или нет, чтобы не возвращать обработчик из предложения for. Мой пример ограничивается тем, что обработчик только заканчивается, когда ничего не соответствует.

добавление кросс-браузерной совместимости, я обычно делаю это так:

var addEvent = function (element, eventName, fn, useCapture) {
  if (element.addEventListener) {
    element.addEventListener(eventName, fn, useCapture);
  }
  else if (element.attachEvent) {
    element.attachEvent(eventName, function (e) {
      fn.apply(element, arguments);
    }, useCapture);
  }
};

это кросс-браузер совместимый код для присоединения прослушивателя/обработчика событий, включая перезапись this в IE, чтобы быть элементом, как и jQuery делает для своих обработчиков событий. Есть масса аргументов, чтобы иметь некоторые биты jQuery в виду ;)

Как насчет этого:

демо jsBin

document.onclick = function(event){
  var hasParent = false;
    for(var node = event.target; node != document.body; node = node.parentNode)
    {
      if(node.id == 'div1'){
        hasParent = true;
        break;
      }
    }
  if(hasParent)
    alert('inside');
  else
    alert('outside');
} 

чтобы скрыть элемент щелчком за его пределами я обычно применяю такой простой код:

var bodyTag = document.getElementsByTagName('body');
var element = document.getElementById('element'); 
function clickedOrNot(e) {
	if (e.target !== element) {
		// action in the case of click outside 
		bodyTag[0].removeEventListener('click', clickedOrNot, true);
	}	
}
bodyTag[0].addEventListener('click', clickedOrNot, true);