Як я не можу запобігти запусканню події onclick батьків при натисканні на якір дитини?


348

Наразі я використовую jQuery, щоб зробити ключ, який можна натиснути на 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>

Відповіді:


460

Пузир подій переходить до найвищої точки DOM, на якій додано подію натискання. Отже, у вашому прикладі, навіть якщо у діві не було явно інших елементів, які можна чітко натискати, кожен дочірній елемент діва буде перетворювати свою подію клацання до DOM до тих пір, поки обробник подій клацання 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;
});

Ви також можете приєднати обробник подій клацання до ваших посилань, який наказує їм припинити спливання подій після виконання власного обробника:

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

3
Чудова відповідь. Приємно знати, що є і варіанти.
Джонатан Уотні

4
+1! Приєднання обробника кліків за допомогою stopPropagation - це дуже приємний трюк, дякую!
Томас

2
якщо у вас було купу елементів, на яких ви хотіли запобігти поширенню, ви можете знайти їх батьківський елемент і попередити його також не пузати. Отже, замість перехоплення всіх посилань у діві, скажімо, наприклад, просто перехопіть клацання навіть на самому діві і не дайте йому вийти вище, і ви налаштовані.
sucitivel

21
Використовувати if( e.target !== this) return;у батьків краще, ніж e.stopPropagation()у дитини, оскільки ви ніколи не знаєте, чи хтось інший приєднує якийсь обробник до дітей, чи якщо бібліотека повинна приєднати обробку до дитини (і ви не хочете возитися з кодом бібліотеки). Це краще розділення проблем.
UTF_or_Death

3
Якщо встановити if( e.target !== this) return;чек у батьків, це означає, що якщо хтось із інших дітей цього батька, у яких немає власних обробників onClick, натискається, нічого не відбувається. Тож марно для ситуації, коли у вас є, наприклад, діва, яка може бути доступною для натискання. e.stopPropagation()працює добре, проте.
derf26

101

Використовуйте метод 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 рішення. 10х!
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

Якщо у розділі, який можна натиснути, у вас декілька елементів, слід зробити це:

$('#clickable *').click(function(e){ e.stopPropagation(); });

8

Використання return false;або e.stopPropogation();не дозволить виконувати подальший код. Він зупинить потік в цій точці сам.


Так, це важливо - наткнувся на це сам. Але відповідь, наведена вище від Рекса, корисна - може отримати елемент, який був натиснутий, а в деяких випадках використовувати це в логіці, яку ви намагаєтеся зупинити. .target.nodeName також був корисним для отримання чіткого уявлення про те, що потрапило.
Watercayman


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

Потрібно зупинити події, щоб досягти (бульбашки до) батьків (діва). Ознайомтеся з частиною про бульбашку тут , а також інформацію про API jQuery тут .


Класно. Дякуємо за інформацію про кипучу подію.
Джонатан Уотні

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, ось я його вирішив.

scss:

#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 для дочірнього модального (поділу вмісту) подій клацання миші, не можна досягти функції "closeLogin" батьківського елемента.

Це зробило для мене хитрість, і я зміг створити модальний ефект за допомогою 2 простих дівок.


-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;"
Андре Швайгофер

-5
<a onclick="return false;" href="http://foo.com">I want to ignore my parent's onclick event.</a>

5
Це також запобігає навігації посилання.
Rex M

Так, чи не робити те, що потрібно ?. Або потрібно бути невегаром?
andres descalzo
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.