Bagaimana saya mencegah acara onclick orang tua dari menembak ketika jangkar anak diklik?

346

Saat ini saya menggunakan jQuery untuk membuat div yang dapat diklik dan dalam div ini saya juga memiliki jangkar. Masalah yang saya hadapi adalah ketika saya mengklik sebuah anchor, kedua event klik itu menyala (untuk div dan anchor). Bagaimana cara mencegah acara onclick div dari menembak ketika jangkar diklik?

Berikut kode yang rusak:

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>
Jonathon Watney
sumber

Jawaban:

458

Acara menggelembung ke titik tertinggi di DOM tempat acara klik dilampirkan. Jadi dalam contoh Anda, bahkan jika Anda tidak memiliki elemen lain yang dapat diklik secara eksplisit di div, setiap elemen anak dari div akan menggelembungkan acara klik mereka ke atas DOM hingga penangan event klik DIV menangkapnya.

Ada dua solusi untuk ini adalah memeriksa untuk melihat siapa yang sebenarnya memulai acara tersebut. jQuery melewati objek eventargs bersama acara:

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

Anda juga dapat melampirkan pengendali acara klik ke tautan Anda yang memberi tahu mereka untuk berhenti menggelegak setelah penangan mereka menjalankan:

$("#clickable a").click(function(e) {
   // Do something
   e.stopPropagation();
});
Rex M
sumber
3
Jawaban yang bagus Senang mengetahui ada pilihan juga.
Jonathon Watney
4
+1! Melampirkan pengendali klik dengan stopPropagation adalah trik yang sangat bagus, terima kasih!
Thomas
2
jika Anda memiliki banyak elemen yang ingin Anda hindari propagasi, Anda bisa menemukan elemen induknya dan mencegahnya agar tidak menggelembung di sana juga. Jadi, alih-alih mencegat semua tautan di div, katakanlah misalnya - cukup sadap klik bahkan pada div itu sendiri dan cegah agar tautannya tidak semakin tinggi dan Anda sudah siap.
sucitivel
21
Menggunakan if( e.target !== this) return;di orangtua lebih baik daripada e.stopPropagation()di anak karena Anda tidak pernah tahu jika orang lain melampirkan pawang ke anak-anak, atau jika perpustakaan harus melampirkan pawang ke anak (dan Anda tidak ingin mengacaukan dengan kode perpustakaan). Ini adalah pemisahan keprihatinan yang lebih baik.
UTF_or_Death
3
Menempatkan tanda if( e.target !== this) return;centang di induk berarti bahwa jika salah satu dari anak-anak lain dari orang tua yang tidak memiliki penangan klik sendiri diklik, maka tidak ada yang terjadi. Jadi tidak ada gunanya untuk situasi di mana Anda memiliki misalnya div induk diklik. e.stopPropagation()bekerja dengan baik.
derf26
100

Gunakan metode stopPropagation , lihat contoh:

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

Seperti yang dikatakan oleh jQuery Docs:

stopPropagation Metode mencegah acara melelehkan pohon DOM, mencegah penangan orang tua diberitahu tentang acara tersebut.

Ingatlah bahwa itu tidak benar menghalangi pendengar lain untuk menangani acara ini (mis. Lebih dari satu penangan klik untuk sebuah tombol), jika itu bukan efek yang diinginkan, Anda harus menggunakannya stopImmediatePropagation.

Bersihkan
sumber
48

Di sini solusi saya untuk semua orang di luar sana mencari kode non-jQuery (javascript murni)

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

Kode Anda tidak akan dieksekusi jika diklik pada anak-anak orang tua

Sabaz
sumber
1
Ini bekerja untuk saya, saya membutuhkan solusi non-JS / jQuery. 10x!
LA
Jawaban yang bagus Saya baru saja melewati acara tersebut secara langsung. Jadi saya tidak menggunakan window.event, yang MDN tidak menyarankan: developer.mozilla.org/en-US/docs/Web/API/Window/event . Jika Anda dapat meluangkan waktu, saya akan sangat menghargai jika Anda dapat berkomentar mengapa Anda menggunakan window.event(mungkin itu adalah masalah yang ada pada tahun 2015 atau saya gagal memahami alasannya).
RM
15

Anda juga dapat mencoba ini

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

Jika Anda tidak berniat untuk berinteraksi dengan elemen dalam / dalam hal apa pun, maka solusi CSS mungkin berguna untuk Anda.

Cukup atur elemen dalam ke pointer-events: none

dalam kasus Anda:

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

atau untuk menargetkan semua elemen dalam secara umum:

.clickable * {
    pointer-events: none;
}

Peretasan mudah ini menyelamatkan saya banyak waktu saat berkembang dengan ReactJS

Dukungan peramban dapat ditemukan di sini: http://caniuse.com/#feat=pointer-events

Hooman Askari
sumber
8

Jika Anda memiliki banyak elemen di div yang dapat diklik, Anda harus melakukan ini:

$('#clickable *').click(function(e){ e.stopPropagation(); });
Ivan Ivković
sumber
8

Menggunakan return false;atau e.stopPropogation();tidak akan membiarkan kode lebih lanjut dieksekusi. Ini akan berhenti mengalir pada titik ini sendiri.

Imamudin Naseem
sumber
Ya, ini penting - lari ke ini sendiri. Tetapi jawaban di atas dari Rex sangat membantu - bisa mendapatkan elemen yang diklik, dan dalam beberapa kasus menggunakan ini dalam logika yang Anda coba hentikan. .target.nodeName juga membantu mendapatkan gagasan yang jelas tentang apa yang dipukul.
Watercayman
8

Menulis jika ada yang butuh (bekerja untuk saya):

event.stopImmediatePropagation()

Dari solusi ini .

Bahadir Tasdemir
sumber
4

Alternatif Sebaris:

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

Berikut ini contoh menggunakan Angular 2+

Misalnya, jika Anda ingin menutup Komponen Modal jika pengguna mengklik di luarnya:

// 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();
}
Steve Brush
sumber
1

Anda harus menghentikan acara dari mencapai (menggelegak ke) orang tua (div). Lihat bagian tentang menggelegak di sini , dan info API khusus jQuery di sini .

Matt Ball
sumber
Keren. Terima kasih atas info tentang acara yang menggelegak.
Jonathon Watney
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>

Pramod Kharade
sumber
0

Untuk menentukan beberapa sub elemen sebagai tidak dapat ditulis, tulis hierarki css seperti pada contoh di bawah ini.

Dalam contoh ini saya menghentikan propagasi ke elemen (*) di dalam td di dalam tr di dalam tabel dengan kelas ".subtable"

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

});
pengguna3202819
sumber
0

AbaikanParent () adalah solusi JavaScript murni.

Ini berfungsi sebagai lapisan perantara yang membandingkan koordinat klik mouse dengan koordinat elemen anak. Dua langkah implementasi sederhana:

1. Masukkan kode ignParent () pada halaman Anda.

2. Alih-alih onclick asli orang tua = "parentEvent ();" , menulis:

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

Anda dapat mengirimkan ID dari sejumlah elemen anak ke fungsi, dan mengecualikan yang lain.

Jika Anda mengklik salah satu elemen anak, acara induk tidak menyala. Jika Anda mengklik orangtua, tetapi tidak pada salah satu elemen anak [disediakan sebagai argumen], acara induk dipecat.

kode ignParent () pada Github

Fom
sumber
0

Jika berada dalam konteks sebaris, dalam HTML coba ini:

onclick="functionCall();event.stopPropagation();
Gleno
sumber
-1

Jika seseorang memiliki masalah ini menggunakan Bereaksi, ini adalah bagaimana saya menyelesaikannya.

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

Pembuatan komponen ():

render() {
    ...
    return (
        <div id='loginBackdrop' onClick={this.props.closeLogin}>
            <div id='loginFrame' onClick={(e)=>{e.preventDefault();e.stopPropagation()}}>
             ... [modal content] ...
            </div>
        </div>
    )
}

Dengan menambahkan fungsi onClick untuk aktivitas klik mouse modal anak (konten div) dicegah untuk mencapai fungsi 'closeLogin' dari elemen induk.

Ini melakukan trik untuk saya dan saya dapat membuat efek modal dengan 2 div sederhana.

Claudio
sumber
-3

tambahkan asebagai berikut:

<a href="http://foo.com" onclick="return false;">....</a>

atau return false;dari click handler untuk #clickablelike:

  $("#clickable").click(function() {
        var url = $("#clickable a").attr("href");
        window.location = url;
        return false;
   });
TheVillageIdiot
sumber
-3

Semua solusi itu rumit dan jscript. Ini adalah versi paling sederhana:

var IsChildWindow=false;

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


function ChildClick()
{
    IsChildWindow=true;
    //Do ur work here    
}
ratnesh
sumber
3
saya pikir Anda membuat kesalahan di baris "IsChildWindow == false;" - bukankah seharusnya "IsChildWindow = false;"?
Andre Schweighofer
-5
<a onclick="return false;" href="http://foo.com">I want to ignore my parent's onclick event.</a>
andres descalzo
sumber
5
Ini juga mencegah tautan dari navigasi.
Rex M
Ya atau tidak apa yang dibutuhkan? Atau perlu nevegar?
andres descalzo