Как предотвратить запуск события onclick одного из родителей при нажатии на дочерний якорь?

349

В настоящее время я использую 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>
Джонатон Уотни
источник

Ответы:

461

События всплывают на самую высокую точку в DOM, к которой было прикреплено событие щелчка. Таким образом, в вашем примере, даже если у вас не было никаких других явных кликабельных элементов в div, каждый дочерний элемент div отправлял бы свое событие click вверх по DOM до тех пор, пока обработчик события click 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;
});

Вы также можете прикрепить обработчик события click к вашим ссылкам, которые сообщат им, чтобы они прекратили всплытие событий после выполнения их собственного обработчика:

$("#clickable a").click(function(e) {
   // Do something
   e.stopPropagation();
});
Рекс М
источник
3
Отличный ответ. Приятно знать, что есть варианты тоже.
Джонатон Уотни
4
+1! Присоединение обработчика кликов с помощью stopPropagation - очень хороший трюк, спасибо!
Томас
2
если у вас есть набор элементов, на которых вы хотите предотвратить распространение, вы можете найти их родительский элемент и заголовок, чтобы он тоже не пузырился там. Так что вместо того, чтобы перехватывать все ссылки в div, скажем, например, просто перехватить щелчок даже на самом div и не дать ему подняться выше, и все готово.
suctivel
21
Использование if( e.target !== this) return;в родительском объекте лучше, чем e.stopPropagation()в дочернем, поскольку вы никогда не знаете, присоединяет ли кто-либо другой обработчик к дочерним элементам, или если библиотека должна прикрепить обработчик к дочернему элементу (и вы не хотите связываться с кодом библиотеки). Это лучшее разделение проблем.
UTF_or_Death
3
Установка if( e.target !== this) return;флажка в родительском элементе означает, что если щелкнуть любой другой дочерний элемент этого родительского объекта, у которого нет собственных обработчиков onClick, то ничего не произойдет. Так что это бесполезно для ситуации, когда у вас есть, например, интерактивный родительский div. e.stopPropagation()работает нормально однако.
derf26
102

Используйте метод stopPropagation , см. Пример:

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

Как сказал JQuery Docs:

stopPropagation Метод предотвращает всплытие события в DOM-дереве, предотвращая уведомление любых родительских обработчиков о событии.

Имейте в виду, что это не мешает другим слушателям обрабатывать это событие (например, более одного обработчика щелчка для кнопки), если это нежелательный эффект, вы должны использовать stopImmediatePropagationвместо этого.

Клейтон
источник
48

Здесь мое решение для всех, кто ищет не jQuery-код (чистый javascript)

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

Ваш код не будет выполнен, если нажать на потомков родителей

Sabaz
источник
1
Это сработало для меня, мне нужно решение не-JS / jQuery. 10x!
LA
Отличный ответ. Я только что прошел мероприятие напрямую. Поэтому я не использовал то window.event, что не одобряет MDN: developer.mozilla.org/en-US/docs/Web/API/Window/event . Если вы можете сэкономить время, я был бы признателен, если бы вы могли прокомментировать, почему вы использовали window.event(возможно, это проблема, существовавшая в 2015 году, или я не смог понять причину).
RMo
15

Вы также можете попробовать это

$("#clickable").click(function(event) {
   var senderElementName = event.target.tagName.toLowerCase();
   if(senderElementName === 'div')
   {
       // do something here 
   } 
   else
   {
      //do something with <a> tag
   }
});
Рашад Аннара
источник
14

Если вы не собираетесь взаимодействовать с внутренним элементом (ами) в любом случае, тогда вам может пригодиться решение CSS.

Просто установите внутренний элемент / ы в pointer-events: none

в твоем случае:

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

или предназначаться для всех внутренних элементов вообще:

.clickable * {
    pointer-events: none;
}

Этот простой хак сэкономил мне много времени при разработке с ReactJS

Поддержка браузера может быть найдена здесь: http://caniuse.com/#feat=pointer-events

Хуман Аскари
источник
8

Если у вас есть несколько элементов в интерактивном div, вы должны сделать это:

$('#clickable *').click(function(e){ e.stopPropagation(); });
Иван Ивкович
источник
8

Использование return false;или e.stopPropogation();не позволит выполнить следующий код. Это остановит поток в этой самой точке.

Имамудин Насим
источник
Да, это важно - столкнулся с этим сам. Но ответ выше от Рекса полезен - может получить элемент, по которому щелкнули, и в некоторых случаях использовать это в логике, которую вы пытаетесь остановить. .target.nodeName также помогло получить четкое представление о том, что было поражено.
Водный Кайман
8

Пишу, если кому-то нужно (работал на меня):

event.stopImmediatePropagation()

Из этого решения.

Бахадир Тасдемир
источник
4

Встроенная альтернатива:

<div>
    <!-- Other content. -->
    <a onclick='event.stopPropagation();' href="http://foo.com">I don't want #clickable to handle this click event.</a>
</div>
Мэтт Уайет
источник
3

Вот пример использования 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();
}
Стив Браш
источник
1

Вам нужно, чтобы событие не достигло (не доходило до) родителя (div). Смотрите часть о пузырях здесь , и jQuery-специфическую информацию об API здесь .

Мэтт Болл
источник
Прохладно. Спасибо за информацию о событиях.
Джонатон Уотни
1

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>

Прамод Хараде
источник
0

Чтобы указать некоторый подэлемент как неприкасаемый, напишите иерархию css, как в примере ниже.

В этом примере я прекращаю распространение на любые элементы (*) внутри td внутри tr внутри таблицы с классом ".subtable"

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

});
user3202819
источник
0

ignoreParent () - это чистое решение JavaScript.

Он работает в качестве промежуточного слоя, который сравнивает координаты щелчка мыши с координатами дочернего элемента / элементов. Два простых шага реализации:

1. Поместите код ignoreParent () на свою страницу.

2. Вместо исходного родительского onclick = "parentEvent ();" , записывать:

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

Вы можете передавать идентификаторы любого количества дочерних элементов в функцию и исключать другие.

Если вы нажали на один из дочерних элементов, родительское событие не сработает. Если вы щелкнули по родительскому элементу, но не по дочернему элементу [предоставляется в качестве аргументов], родительское событие вызывается.

код ignoreParent () на Github

ФОМ
источник
0

Если это во встроенном контексте, в HTML попробуйте это:

onclick="functionCall();event.stopPropagation();
Глено
источник
-1

В случае, если у кого-то возникла эта проблема с использованием React, я так решил ее.

СКС:

#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() {
    ...
    return (
        <div id='loginBackdrop' onClick={this.props.closeLogin}>
            <div id='loginFrame' onClick={(e)=>{e.preventDefault();e.stopPropagation()}}>
             ... [modal content] ...
            </div>
        </div>
    )
}

Благодаря добавлению функции onClick для дочерних модальных (content div) событий щелчка мыши предотвращается достижение функции closeLogin родительского элемента.

Это помогло мне, и я смог создать модальный эффект с двумя простыми делами.

Claudio
источник
-3

добавить 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;
   });
TheVillageIdiot
источник
-3

Все решения сложны и из jscript. Вот самая простая версия:

var IsChildWindow=false;

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


function ChildClick()
{
    IsChildWindow=true;
    //Do ur work here    
}
ratnesh
источник
3
я думаю, что вы допустили ошибку в строке "IsChildWindow == false;" - не должно ли быть "IsChildWindow = false;"?
Андре Швайгхофер
-5
<a onclick="return false;" href="http://foo.com">I want to ignore my parent's onclick event.</a>
Андрес Дескальзо
источник
5
Это также предотвращает переход по ссылке.
Рекс М
Да или не то что нужно? Или нужно быть невегар?
Andres Descalzo