Apa perbedaan antara event.stopPropagation dan event.preventDefault?

834

Mereka tampaknya melakukan hal yang sama ...
Apakah yang satu modern dan yang lama? Atau apakah mereka didukung oleh browser yang berbeda?

Ketika saya menangani acara sendiri (tanpa kerangka kerja) saya selalu memeriksa keduanya dan mengeksekusi keduanya jika ada. (Saya juga return false, tetapi saya punya perasaan yang tidak bekerja dengan acara terlampir node.addEventListener).

Jadi mengapa keduanya? Haruskah saya terus memeriksa keduanya? Atau apakah sebenarnya ada perbedaan?

(Saya tahu, banyak pertanyaan, tapi semuanya semua sama =))

Rudie
sumber

Jawaban:

1015

stopPropagation menghentikan acara dari menggelegak rantai acara.

preventDefault mencegah tindakan default yang dilakukan browser pada acara tersebut.

Contohnya

mencegah Kerusakan

$("#but").click(function (event) {
  event.preventDefault()
})
$("#foo").click(function () {
  alert("parent click event fired!")
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo">
  <button id="but">button</button>
</div>

stopPropagation

$("#but").click(function (event) {
  event.stopPropagation()
})
$("#foo").click(function () {
  alert("parent click event fired!")
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo">
  <button id="but">button</button>
</div>

Dengan stopPropagation, hanya buttonpenangan klik yang dipanggil sementara divpenangan klik tidak pernah menyala.

Di mana seolah-olah Anda menggunakan preventDefault, hanya tindakan default browser yang dihentikan tetapi penangan klik div masih menyala.

Berikut adalah beberapa dokumen tentang properti acara DOM dan metode dari MDN:

Untuk IE9 dan FF Anda bisa menggunakan preventDefault & stopPropagation.

Untuk mendukung IE8 dan lebih rendah ganti stopPropagationdengan cancelBubbledan ganti preventDefaultdenganreturnValue

Raynos
sumber
Jadi mereka sangat berbeda? Apakah IE memiliki dua metode acara yang berbeda untuk itu juga? (Mungkinkah mereka sama ??) Aneh bahwa kerangka melakukan keduanya dalam event.stopfungsinya ... Juga aneh aku tidak pernah punya masalah dengan itu. Saya menggunakan banyak menggelegak. Terima kasih untuk contohnya!
Rudie
@Rudie mengomentari dukungan browser.
Raynos
7
Perlu dicatat (jika Anda tidak melihat dokumen MSDN) bahwa cancelBubbledan returnValuekeduanya adalah properti (jadi harus ditetapkan cancelBubble = true;), dan itu preventDefaultdan stopPropagationmetode (jadi harus disebut preventDefault();)
freefaller
1
@Raynos, hanya satu catatan: event.stopPropagation () tidak hanya menghentikan acara dari menggelegak rantai acara, tetapi juga menghentikan propagasi acara dalam fase penangkapan ( developer.mozilla.org/en-US/docs/Web/ API / Event / stopPropagation )
Yuci
1
Akan sangat membantu untuk mengetahui apa tindakan default untuk klik tombol jadi saya bisa alasan mengapa stopDefault()tidak bekerja dengan cara yang sama stopPropagation(). Jika tindakan default tidak memanggil onclickmetode apa itu?
d512
249

Terminologi

Dari quirksmode.org :

Pengambilan acara

Saat Anda menggunakan penangkapan acara

               | |
--------------- | | -----------------
| element1 | | |
| ----------- | | ----------- |
| | element2 \ / | |
| ------------------------- |
| Acara CAPTURING |
-----------------------------------

pengendali event elemen1 pertama yang terbakar, pengendali event elemen2 terakhir.

Gelembung acara

Saat Anda menggunakan acara bubbling

               / \
--------------- | | -----------------
| element1 | | |
| ----------- | | ----------- |
| | elemen2 | | | |
| ------------------------- |
| Acara BUBBLING |
-----------------------------------

pengendali event elemen2 pertama yang dipecat, pengendali event elemen1 terakhir.

Setiap peristiwa yang terjadi dalam model acara W3C ditangkap pertama kali hingga mencapai elemen target dan kemudian muncul lagi .

                 | | / \
----------------- | | - | | -----------------
| element1 | | | | |
| ------------- | | - | | ----------- |
| | element2 \ / | | | |
| -------------------------------- |
| W3C model acara |
------------------------------------------

Antarmuka

Dari w3.org , untuk acara tangkap :

Jika penangkapan EventListeneringin mencegah pemrosesan lebih lanjut dari peristiwa itu terjadi dapat memanggil stopPropagationmetode Eventantarmuka. Ini akan mencegah pengiriman acara lebih lanjut, meskipun tambahan EventListenersterdaftar di tingkat hierarki yang sama akan tetap menerima acara tersebut. Setelah metode acara stopPropagation dipanggil, panggilan lebih lanjut ke metode tersebut tidak memiliki efek tambahan. Jika tidak ada penangkap tambahan yang ada dan stopPropagationbelum dipanggil, acara memicu yang sesuai EventListenerspada target itu sendiri.

Untuk acara bubbling :

Pengatur kejadian dapat memilih untuk mencegah penyebaran acara lebih lanjut dengan memanggil stopPropagationmetode Eventantarmuka. Jika ada yang EventListenermemanggil metode ini, semua tambahan EventListenerspada saat ini EventTargetakan dipicu tetapi menggelegak akan berhenti pada tingkat itu. Hanya satu panggilan ke stopPropagationdiperlukan untuk mencegah menggelegak lebih lanjut.

Untuk pembatalan acara :

Pembatalan dilakukan dengan memanggil para Event's preventDefault metode. Jika satu atau lebih EventListenerspanggilan preventDefaultselama fase acara mengalir tindakan default akan dibatalkan.

Contohnya

Dalam contoh berikut, klik pada tautan di browser web memicu aliran acara (pendengar acara dieksekusi) dan tindakan default target acara (tab baru dibuka).

HTML:

<div id="a">
  <a id="b" href="http://www.google.com/" target="_blank">Google</a>
</div>
<p id="c"></p>

JavaScript:

var el = document.getElementById("c");

function capturingOnClick1(ev) {
    el.innerHTML += "DIV event capture<br>";
}

function capturingOnClick2(ev) {
    el.innerHTML += "A event capture<br>";
}

function bubblingOnClick1(ev) {
    el.innerHTML += "DIV event bubbling<br>";
}

function bubblingOnClick2(ev) {
    el.innerHTML += "A event bubbling<br>";
}

// The 3rd parameter useCapture makes the event listener capturing (false by default)
document.getElementById("a").addEventListener("click", capturingOnClick1, true);
document.getElementById("b").addEventListener("click", capturingOnClick2, true);
document.getElementById("a").addEventListener("click", bubblingOnClick1, false);
document.getElementById("b").addEventListener("click", bubblingOnClick2, false);

Contoh 1 : menghasilkan output

DIV event capture
A event capture
A event bubbling
DIV event bubbling

Contoh 2 : menambahkan stopPropagation()ke fungsi

function capturingOnClick1(ev) {
    el.innerHTML += "DIV event capture<br>";
    ev.stopPropagation();
}

menghasilkan output

DIV event capture

Pendengar acara mencegah penyebaran lebih lanjut ke bawah dan ke atas dari acara tersebut. Namun itu tidak mencegah tindakan default (pembukaan tab baru).

Contoh 3 : menambahkan stopPropagation()ke fungsi

function capturingOnClick2(ev) {
    el.innerHTML += "A event capture<br>";
    ev.stopPropagation();
}

atau fungsinya

function bubblingOnClick2(ev) {
    el.innerHTML += "A event bubbling<br>";
    ev.stopPropagation();
}

menghasilkan output

DIV event capture
A event capture
A event bubbling

Ini karena kedua pendengar acara terdaftar pada target acara yang sama. Pendengar acara mencegah penyebaran lebih lanjut dari acara tersebut. Namun mereka tidak mencegah tindakan default (pembukaan tab baru).

Contoh 4 : menambahkan preventDefault()ke fungsi apa pun, misalnya

function capturingOnClick1(ev) {
    el.innerHTML += "DIV event capture<br>";
    ev.preventDefault();
}

mencegah tab baru dari pembukaan.

Ashkan
sumber
23
Terima kasih atas perbedaan yang lebih dalam antara menangkap dan menggelegak sementara jawaban lainnya hanya membahas masalah jQuery.
floribon
@ floribon mengatakan Anda tidak punya niat untuk menyinggung raynos atas jawabannya.
Mahi
3
@Mahi apa? Saya hanya mengatakan fakta, jawaban yang diterima menggunakan jQuery yang tidak diasumsikan oleh OP, jadi bagi saya itu bukan jawaban yang sebenarnya. Nah, itu baru fakta teknis, bukan masalah pribadi dan tidak ada yang tersinggung.
floribon
2
Jawaban Anda sangat sistematis dan menunjukkan dengan baik apa yang sedang terjadi. Awalnya saya tidak ingin mengganggu Anda dan membuat beberapa perubahan pada jawaban Anda sendiri, karena saya pikir itu bisa ditingkatkan sedikit untuk kejelasan. Jawaban ini menjelaskan model acara untuk pemula dan karena itu, saya pikir setiap bantuan yang dapat kami berikan kepada para pemula sangat membantu. Saran edit saya telah ditolak oleh argumen umum, yang tidak saya setujui. Jika Anda, @Ashkan, merasa bahwa perubahan kecil ini dapat membantu meningkatkan jawabannya, silakan gabungkan.
mucaho
68

return false;


return false; melakukan 3 hal yang terpisah ketika Anda menyebutnya:

  1. event.preventDefault() - Ini menghentikan perilaku default browser.
  2. event.stopPropagation() - Ini mencegah acara dari menyebarkan (atau "menggelegak") DOM.
  3. Menghentikan eksekusi panggilan balik dan segera kembali saat dipanggil.

Perhatikan bahwa perilaku ini berbeda dari penangan acara normal (non-jQuery), di mana, terutama, return falsetidak menghentikan peristiwa dari menggelegak.

preventDefault ();


preventDefault(); melakukan satu hal: Ini menghentikan perilaku default browser.

Kapan menggunakannya?


Kita tahu apa yang mereka lakukan tetapi kapan menggunakannya? Cukup tergantung pada apa yang ingin Anda capai. Gunakan preventDefault();jika Anda ingin "hanya" mencegah perilaku browser default. Gunakan return false; ketika Anda ingin mencegah perilaku browser default dan mencegah acara tersebut menyebarkan DOM. Dalam sebagian besar situasi di mana Anda akan menggunakan return false; apa yang sebenarnya Anda inginkan adalah preventDefault().

Contoh:


Mari kita coba pahami dengan contoh:

Kita akan melihat contoh JAVASCRIPT murni

Contoh 1:

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
  function executeChild() {
    alert('Link Clicked');
  }

  function executeParent() {
    alert('div Clicked');
  }
</script>

Jalankan kode di atas Anda akan melihat hyperlink 'Klik di sini untuk mengunjungi stackoverflow.com' sekarang jika Anda mengklik tautan itu terlebih dahulu Anda akan mendapatkan peringatan javascript Tautan Diklik Selanjutnya Anda akan mendapatkan div tanda javascript diklik dan segera Anda akan diarahkan ke stackoverflow.com.

Contoh 2:

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
  function executeChild() {
    event.preventDefault();
    event.currentTarget.innerHTML = 'Click event prevented'
    alert('Link Clicked');
  }

  function executeParent() {
    alert('div Clicked');
  }
</script>

Jalankan kode di atas Anda akan melihat hyperlink 'Klik di sini untuk mengunjungi stackoverflow.com' sekarang jika Anda mengklik tautan itu terlebih dahulu Anda akan mendapatkan peringatan javascript Tautan Diklik Selanjutnya Anda akan mendapatkan div tanda javascript diklik Selanjutnya Anda akan melihat hyperlink ' Klik di sini untuk mengunjungi stackoverflow.com 'diganti oleh teks' Klik acara dicegah 'dan Anda tidak akan diarahkan ke stackoverflow.com. Ini disebabkan karena metode event.preventDefault () yang kami gunakan untuk mencegah aksi klik default menjadi terpicu.

Contoh 3:

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
  function executeChild() {
    event.stopPropagation();
    event.currentTarget.innerHTML = 'Click event prevented'
    alert('Link Clicked');
  }

  function executeParent() {
    alert('div Clicked');
  }
</script>

Kali ini jika Anda mengklik Tautkan fungsi executeParent () tidak akan dipanggil dan Anda tidak akan mendapatkan div tanda javascript diklik kali ini. Ini karena kami telah mencegah penyebaran ke div induk menggunakan metode event.stopPropagation (). Selanjutnya Anda akan melihat hyperlink 'Klik di sini untuk mengunjungi stackoverflow.com' digantikan oleh teks 'Acara klik akan dieksekusi' dan segera Anda akan diarahkan ke stackoverflow.com. Ini karena kami belum mencegah tindakan klik default dari memicu kali ini menggunakan metode event.preventDefault ().

Contoh 4:

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
  function executeChild() {
    event.preventDefault();
    event.stopPropagation();
    event.currentTarget.innerHTML = 'Click event prevented'
    alert('Link Clicked');
  }

  function executeParent() {
    alert('Div Clicked');
  }
</script>

Jika Anda mengklik Tautan, fungsi executeParent () tidak akan dipanggil dan Anda tidak akan mendapatkan peringatan javascript. Ini karena kami telah mencegah penyebaran ke div induk menggunakan metode event.stopPropagation (). Selanjutnya Anda akan melihat hyperlink 'Klik di sini untuk mengunjungi stackoverflow.com' digantikan oleh teks 'Klik acara dicegah' dan Anda tidak akan diarahkan ke stackoverflow.com. Ini karena kami telah mencegah aksi klik default dari memicu kali ini menggunakan metode event.preventDefault ().

Contoh 5:

Untuk return false, saya memiliki tiga contoh dan semuanya tampak melakukan hal yang persis sama (hanya mengembalikan false), tetapi dalam kenyataannya hasilnya sangat berbeda. Inilah yang sebenarnya terjadi di masing-masing di atas.

kasus:

  1. Mengembalikan false dari pengendali event inline mencegah browser menavigasi ke alamat tautan, tetapi itu tidak menghentikan acara agar tidak menyebar melalui DOM.
  2. Mengembalikan false dari pengendali event jQuery mencegah browser menavigasi ke alamat tautan dan menghentikan acara agar tidak menyebar melalui DOM.
  3. Mengembalikan false dari event handler DOM reguler tidak menghasilkan apa-apa.

Akan melihat ketiga contohnya.

  1. Inline return false.

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='return false'>Click here to visit stackoverflow.com</a>
</div>
<script>
  var link = document.querySelector('a');

  link.addEventListener('click', function() {
    event.currentTarget.innerHTML = 'Click event prevented using inline html'
    alert('Link Clicked');
  });


  function executeParent() {
    alert('Div Clicked');
  }
</script>

  1. Mengembalikan false dari penangan event jQuery.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
  <a href='https://stackoverflow.com'>Click here to visit stackoverflow.com</a>
</div>
<script>
  $('a').click(function(event) {
    alert('Link Clicked');
    $('a').text('Click event prevented using return FALSE');
    $('a').contents().unwrap();
    return false;
  });
  $('div').click(function(event) {
    alert('Div clicked');
  });
</script>

  1. Mengembalikan false dari pengendali event DOM biasa.

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
  function executeChild() {
    event.currentTarget.innerHTML = 'Click event prevented'
    alert('Link Clicked');
    return false
  }

  function executeParent() {
    alert('Div Clicked');
  }
</script>

Semoga contoh-contoh ini jelas. Coba jalankan semua contoh ini dalam file html untuk melihat cara kerjanya.

Keval Bhatt
sumber
1
Contoh yang bagus, tetapi akan lebih baik tanpa jQuery, karena jQuery memalsukan objek acara, jadi itu berbeda secara teknis.
Rudie
1
@ Rudie Saya memperbarui jawaban saya dan menghapus jquery darinya, dan juga menambahkan contoh untuk return false.
Keval Bhatt
17

Ini adalah kutipan dari sini

Event.preventDefault

Metode preventDefault mencegah acara menjalankan fungsi defaultnya. Misalnya, Anda akan menggunakan preventDefault pada elemen A untuk berhenti mengklik elemen itu dari meninggalkan halaman saat ini:

//clicking the link will *not* allow the user to leave the page 
myChildElement.onclick = function(e) { 
    e.preventDefault(); 
    console.log('brick me!'); 
};

//clicking the parent node will run the following console statement because event propagation occurs
logo.parentNode.onclick = function(e) { 
    console.log('you bricked my child!'); 
};

Sementara fungsionalitas default elemen adalah bricked, event terus melembungkan DOM.

Event.stopPropagation

Metode kedua, stopPropagation, memungkinkan fungsionalitas default acara terjadi tetapi mencegah agar acara tidak menyebar:

//clicking the element will allow the default action to occur but propagation will be stopped...
myChildElement.onclick = function(e) { 
    e.stopPropagation();
    console.log('prop stop! no bubbles!'); 
};

//since propagation was stopped by the child element's onClick, this message will never be seen!
myChildElement.parentNode.onclick = function(e) { 
    console.log('you will never see this message!'); 
};

stopPropagation secara efektif menghentikan elemen orangtua untuk mengetahui tentang peristiwa tertentu pada anaknya.

Meskipun metode penghentian yang sederhana memungkinkan kami menangani acara dengan cepat, penting untuk memikirkan apa yang sebenarnya ingin Anda lakukan dengan menggelegak. Saya berani bertaruh bahwa semua pengembang benar-benar ingin mencegahDefault 90% dari waktu! Salah "menghentikan" suatu peristiwa dapat menyebabkan Anda mengalami banyak masalah; plugin Anda mungkin tidak berfungsi dan plugin pihak ketiga Anda bisa menjadi batu bata. Atau lebih buruk lagi - kode Anda merusak fungsi lain di situs.

VladL
sumber
2

Event.preventDefault- menghentikan perilaku default browser. Sekarang tlah perilaku browser default. Asumsikan Anda memiliki tag jangkar dan telah mendapat atribut href dan tag jangkar ini bersarang di dalam tag div yang telah mendapat event klik. Perilaku default dari anchor tag adalah ketika diklik pada anchor tag yang seharusnya ia navigasikan, tetapi yang dilakukan event.preventDefault adalah menghentikan navigasi dalam hal ini. Tapi itu tidak pernah berhenti dari peristiwa atau eskalasi acara yaitu

<div class="container">
 <a href="#" class="element">Click Me!</a>
</div>

$('.container').on('click', function(e) {
 console.log('container was clicked');
});

$('.element').on('click', function(e) {
  e.preventDefault(); // Now link won't go anywhere
  console.log('element was clicked');
});

Hasilnya akan

"elemen diklik"

"kontainer diklik"

Sekarang event. StopPropation itu berhenti menggelegak acara atau eskalasi acara. Sekarang dengan contoh di atas

$('.container').on('click', function(e) {
  console.log('container was clicked');
});

$('.element').on('click', function(e) {
  e.preventDefault(); // Now link won't go anywhere
  e.stopPropagation(); // Now the event won't bubble up
 console.log('element was clicked');
});

Hasilnya akan

"elemen diklik"

Untuk info lebih lanjut lihat tautan ini https://codeplanet.io/preventdefault-vs-stoppropagation-vs-stopimmediatepropagation/

Subramanian Naya
sumber
1

event.preventDefault(); Menghentikan aksi default suatu elemen agar tidak terjadi.

event.stopPropagation(); Mencegah peristiwa menggelegak pohon DOM, mencegah penangan orang tua diberitahu tentang acara tersebut.

Misalnya, jika ada tautan dengan metode klik terlampir di dalam DIVatau FORMyang juga memiliki metode klik terlampir, itu akan mencegah DIVatau FORMklik metode dari penembakan.

Mike Clark
sumber
-3

$("#but").click(function(event){
console.log("hello");
  event.preventDefault();
 });


$("#foo").click(function(){
 alert("parent click event fired !");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo">
  <button id="but">button</button>
</div>

Manish Singh
sumber