Как предотвратить запуск события 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
    }
});

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


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 также помогло получить четкое представление о том, что было поражено.
Водный Кайман


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

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

});

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 родительского элемента.

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


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

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

3
я думаю, что вы допустили ошибку в строке "IsChildWindow == false;" - не должно ли быть "IsChildWindow = false;"?
Андре Швайгхофер

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.