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

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

26 ответов

Решение

События всплывают на самую высокую точку в 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();
});

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

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

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

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

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

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

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

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

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

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

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

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

или нацелиться на все внутренние элементы в целом:

.clickable * {
    pointer-events: none;
}

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

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

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

<div>
    <!-- Other content. -->
    <a onclick='event.stopPropagation();' href="http://foo.com">I don't want #clickable to handle this click event.</a>
</div>

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

$("#clickable").click(function(event) {
   var senderElementName = event.target.tagName.toLowerCase();
   if(senderElementName === 'div')
   {
       // do something here 
   } 
   else
   {
      //do something with <a> tag
   }
});

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

event.stopImmediatePropagation()

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

Я сравниваю с ev.currentTarget когда this недоступен (React и т. д.).

      $("#clickable").click(function(e) {
    if (e.target === e.currentTarget) {
        window.location = url;
        return true;
    }
})

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

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

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

e.stopPropagation() - правильное решение, но если вы не хотите прикреплять какой-либо обработчик событий к своему внутреннему якорю, вы можете просто прикрепить этот обработчик к своему внешнему div:

e => { e.target === e.currentTarget && window.location = URL; }

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

Если он находится во встроенном контексте, в HTML попробуйте следующее:

onclick="functionCall();event.stopPropagation();

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>

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

Вот решение, отличное от jQuery, которое сработало для меня.

Вы можете проверить, не является ли цель вашим div-элементом, а затем выполнить другое событие щелчка на родительском элементе, после чего вы "вернетесь" из дескриптора.

$('clickable').click(function (event) {
    let div = $(event.target);
    if (! div.is('div')) {
       div.parent().click();
       return;
    }
    // Then Implement your logic here
}

для тех, кто не использует jQuery

      document.querySelector('.clickable').addEventListener('click', (e) =>{
    if(!e.target.classList.contains('clickable')) return
    // place code here
})

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

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

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

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

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

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

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

код ignoreParent() на Github

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

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

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

});

Если щелкнуть дочерний элемент, событие всплывает до родительского и event.target!== event.currentTarget.

Итак, в своей функции вы можете проверить это и вернуться раньше, то есть:

var url = $("#clickable a").attr("href");
$("#clickable").click(function(event) {
    if ( event.target !== event.currentTarget ){
        // user clicked on a child and we ignore that
        return;
    }
    window.location = url;
    return true;
})

Это то, что вы ищете

mousedownмероприятие. это работает для всех элементов DOM, чтобы предотвратить такой обработчик фокуса javascript:

      $('.no-focus').mousedown(function (e) {
   e.prevenDefault()

   // do stuff
}

в vue.js framework, вы можете использовать модификатор следующим образом:

      <span @mousedown.prevent> no focus </span>

Обратите внимание, что использование на входе предотвратит использование обработчика выделения текста.

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

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

Добавлять 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;
   });

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

var IsChildWindow=false;

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


function ChildClick()
{
    IsChildWindow=true;
    //Do ur work here    
}
<a onclick="return false;" href="http://foo.com">I want to ignore my parent's onclick event.</a>
Другие вопросы по тегам