javascript - event.stopPropagation ve event.preventDefault arasındaki fark nedir?


Görünüşe göre aynı şeyi yapıyorlar...
Biri modern, diğeri eski mi? Yoksa farklı tarayıcılar mı destekliyor?

Olayları kendim (çerçeve kullanmadan) yönettiğimde, her zaman her ikisini de kontrol ederim ve mevcutsa her ikisini de çalıştırırım. (Ayrıca return false yapıyorum, ama bunun node.addEventListener ile eklenen olaylarda çalışmadığını hissediyorum).

Peki neden ikisi de? İkisini de kontrol etmeye devam mı etmeliyim? Yoksa gerçekten bir fark var mı?

(Biliyorum, çok soru, ama hepsi bir şekilde aynı =))

Cevap #1

stopPropagation, geçerli olayın yakalama ve kabarcıklanma aşamalarında daha fazla yayılmasını engeller.

preventDefault, tarayıcının o olay üzerinde yaptığı varsayılan işlemi engeller.

Örnekler

preventDefault

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

stopPropagation ile sadece button'ın tıklama işleyicisi çağrılır, div'in tıklama işleyicisi hiçbir zaman çalışmaz.

Oysa ki preventDefault kullanırsanız, yalnızca tarayıcının varsayılan eylemi durdurulur, ancak div'in tıklama işleyicisi yine de çalışır.

Aşağıda MDN'den DOM olay özellikleri ve yöntemleri ile ilgili bazı belgeler bulunmaktadır:

  • event.cancelBubble
  • event.preventDefault()
  • event.returnValue
  • event.stopPropagation()

IE9 ve FF için sadece preventDefault ve stopPropagation kullanabilirsiniz.

IE8 ve altını desteklemek için stopPropagation yerine cancelBubble kullanın ve preventDefault yerine returnValue kullanın

Cevap #2

Terminoloji

quirksmode.org'dan:

Olay yakalama

Olay yakalama kullandığınızda

               | |
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  \ /          |     |
|   -------------------------     |
|        Event CAPTURING          |
-----------------------------------

element1'in olay işleyicisi ilk olarak tetiklenir, element2'nin olay işleyicisi en son tetiklenir.

Olayın kabarcıklanması

Olay kabarmasını kullandığınızda

               / \
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  | |          |     |
|   -------------------------     |
|        Event BUBBLING           |
-----------------------------------

element2'nin olay işleyicisi ilk olarak tetiklenir, element1'in olay işleyicisi en son tetiklenir.

W3C olay modelinde gerçekleşen herhangi bir olay, hedef elemana ulaşana kadar önce yakalanır ve ardından tekrar yukarı doğru yayılır.

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

Arayüz

w3.org'dan, olay yakalama için:

Eğer yakalayan EventListener, olayın daha fazla işlenmesini engellemek istiyorsa, Event arayüzünün stopPropagation metodunu çağırabilir. Bu, olayın daha fazla dağıtılmasını engeller, ancak aynı hiyerarşi seviyesinde kayıtlı ek EventListenerlar hala olayı alır. Bir olayın stopPropagation metodu çağrıldıktan sonra, bu metoda yapılacak ek çağrılar herhangi bir ek etki yaratmaz. Eğer ek yakalayıcılar yoksa ve stopPropagation çağrılmamışsa, olay hedefin üzerindeki uygun EventListenerları tetikler.

Olay kabarması için:

Herhangi bir olay işleyicisi, Event arayüzünün stopPropagation yöntemini çağırarak olayın daha fazla yayılmasını engellemeyi seçebilir. Eğer herhangi bir EventListener bu yöntemi çağırırsa, mevcut EventTarget üzerindeki tüm ek EventListener’lar tetiklenecek, ancak baloncuk oluşumu o seviyede duracaktır. Daha fazla baloncuk oluşmasını engellemek için yalnızca bir kez stopPropagation çağrılması yeterlidir.

Etkinlik iptali için:

İptal, Event'in preventDefault yöntemini çağırarak gerçekleştirilir. Bir veya daha fazla EventListener, olay akışının herhangi bir aşamasında preventDefault çağırırsa, varsayılan eylem iptal edilecektir.

Örnekler

Aşağıdaki örneklerde, web tarayıcısındaki bir köprüye tıklamak olayın akışını tetikler (olay dinleyicileri çalıştırılır) ve olay hedefinin varsayılan eylemini (yeni bir sekme açılır) gerçekleştirir.

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

Örnek 1: bu, çıktıyla sonuçlanır

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

Örnek 2: Fonksiyona stopPropagation() eklemek

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

çıktıda sonuçlar

DIV event capture

Olay dinleyicisi, olayın aşağı ve yukarı doğru yayılmasını engelledi. Ancak varsayılan eylemi (yeni bir sekme açılmasını) engellemedi.

Örnek 3: Fonksiyona stopPropagation() eklemek

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

veya fonksiyon

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

çıktıda sonuçlar

DIV event capture
A event capture
A event bubbling

Bunun nedeni her iki olay dinleyicisinin de aynı olay hedefine kaydedilmiş olmasıdır. Olay dinleyicileri olayın yukarı doğru daha fazla yayılmasını engelledi. Ancak varsayılan eylemi (yeni bir sekmenin açılması) engellemediler.

Örnek 4: herhangi bir fonksiyona, örneğin preventDefault() eklemek

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

yeni bir sekmenin açılmasını engeller.

Cevap #3

false dön;

return false; çağırdığınızda 3 farklı şey yapar:

  1. event.preventDefault() - Tarayıcının varsayılan davranışını durdurur.
  2. event.stopPropagation() - Olayın DOM üzerinde yayılmasını (veya 'yukarı doğru kabarmasını') engeller.
  3. Çağrıldığında geri arama yürütmesini durdurur ve hemen geri döner.

Bu davranışın normal (jQuery dışı) olay işleyicilerinden farklı olduğunu unutmayın; özellikle return false'un olayın yukarı doğru yayılmasını durdurmadığını.

preventDefault();

preventDefault(); bir şeyi yapar: Tarayıcının varsayılan davranışını durdurur.

Ne zaman kullanmalısınız?

Onların ne yaptığını biliyoruz ama ne zaman kullanılacağını? Basitçe söylemek gerekirse, ne başarmak istediğinize bağlıdır. Varsayılan tarayıcı davranışını “sadece” engellemek istiyorsanız preventDefault(); kullanın. Varsayılan tarayıcı davranışını engellemek ve olayın DOM içinde yayılmasını önlemek istiyorsanız return false; kullanın. return false; kullanacağınız çoğu durumda aslında istediğiniz şey preventDefault().

Örnekler:

Örneklerle anlamaya çalışalım:

Saf JAVASCRIPT örneğini göreceğiz

Örnek 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>

Yukarıdaki kodu çalıştırırsanız, hiperlinki ‘Click here to visit stackoverflow.com‘ göreceksiniz. Şimdi o linke tıkladığınızda önce javascript uyarısı Link Clicked görünecek. Sonra javascript uyarısı div Clicked gözükecek ve hemen ardından stackoverflow.com sitesine yönlendirileceksiniz.

Örnek 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>

Yukarıdaki kodu çalıştırırsanız, ‘Click here to visit stackoverflow.com‘ bağlantısını göreceksiniz. Şimdi o bağlantıya tıkladığınızda önce Link Clicked JavaScript uyarısını alırsınız. Sonra div Clicked JavaScript uyarısını alırsınız. Daha sonra ‘Click here to visit stackoverflow.com‘ bağlantısı ‘Click event prevented‘ metni ile değiştirilir ve stackoverflow.com sitesine yönlendirilmezsiniz. Bu, varsayılan tıklama işleminin tetiklenmesini önlemek için kullandığımız event.preventDefault() metodundan kaynaklanmaktadır.

Örnek 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>

Bu sefer eğer Link'e tıklarsanız, executeParent() fonksiyonu çağrılmayacak ve bu sefer javascript uyarısı div Clicked almayacaksınız. Bunun nedeni, event.stopPropagation() yöntemi kullanarak olayı üst div'e iletmesini engellemiş olmamızdır. Sonraki adımda, ‘Click here to visit stackoverflow.com‘ olan hiperlinkin ‘Click event is going to be executed‘ metni ile değiştirildiğini göreceksiniz ve hemen stackoverflow.com'a yönlendirileceksiniz. Bunun nedeni, bu sefer event.preventDefault() yöntemi kullanarak varsayılan tıklama eyleminin tetiklenmesini engellememiş olmamızdır.

Örnek 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>

Eğer Bağlantıya tıklarsanız, executeParent() fonksiyonu çağrılmayacak ve javascript uyarısını almayacaksınız. Bu, olayın üst div'e yayılmasını event.stopPropagation() yöntemiyle engellediğimizden kaynaklanmaktadır. Sonraki adımda, ‘stackoverflow.com'u ziyaret etmek için buraya tıklayın’ bağlantısının, ‘Tıklama olayı engellendi’ metni ile değiştirildiğini göreceksiniz ve stackoverflow.com'a yönlendirilmeyeceksiniz. Bunun nedeni, bu sefer varsayılan tıklama eyleminin event.preventDefault() yöntemiyle tetiklenmesini engellemiş olmamızdır.

Örnek 5:

return false için üç örneğim var ve hepsi tam olarak aynı şeyi yapıyor gibi görünüyor (sadece false döndürüyor), ancak gerçekte sonuçlar oldukça farklı. İşte yukarıdakilerde aslında ne olduğu.

vakalar :

  1. Satır içi bir olay işleyicisinden false döndürmek, tarayıcının bağlantı adresine gitmesini engeller, ancak olayın DOM üzerinden yayılmasını durdurmaz.
  2. Bir jQuery olay işleyicisinden false döndürmek, tarayıcının bağlantı adresine gitmesini önler ve olayın DOM üzerinden yayılmasını durdurur.
  3. Normal bir DOM olay işleyicisinden false döndürmek hiçbir şey yapmaz.

Üç örneği de göreceğiz.

  1. Satır içi false döndür.

<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. Bir jQuery olay işleyicisinden false döndürmek.

<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. Normal bir DOM olay işleyicisinden false döndürmek.

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

Umarım bu örnekler açıktır. Bu örneklerin nasıl çalıştığını görmek için hepsini bir HTML dosyasında çalıştırmayı deneyin.

Cevap #4

Bu buradan alınan alıntıdır

Event.preventDefault

preventDefault yöntemi, bir olayın varsayılan işlevini yerine getirmesini engeller. Örneğin, bir A öğesinde preventDefault kullanarak, o öğeye tıklamanın mevcut sayfadan ayrılmasını durdurabilirsiniz:

//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!'); 
};

Öğenin varsayılan işlevselliği devre dışı bırakılmış olsa da, olay DOM boyunca yukarı doğru yayılmaya devam eder.

Event.stopPropagation

İkinci yöntem olan stopPropagation, olayın varsayılan işlevinin gerçekleşmesine izin verir ancak olayın yayılmasını engeller:

//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, bir çocuğundaki belirli bir olay hakkında üst öğelerin bilgi sahibi olmasını etkili bir şekilde durdurur.

Basit bir durdurma yöntemi olayları hızlı bir şekilde yönetmemize izin verirken, kümeleşme ile tam olarak ne olmasını istediğinizi düşünmek önemlidir. Bahse girerim ki bir geliştirici aslında zamanın %90'ında sadece preventDefault yapmak ister! Olayı yanlış şekilde "durdurmak", ileride size birçok sorun çıkarabilir; eklentileriniz çalışmayabilir ve üçüncü taraf eklentiler bozulabilir. Daha da kötüsü -- kodunuz bir sitedeki diğer işlevleri bozabilir.

Cevap #5

event.preventDefault()
Tarayıcının varsayılan davranışını (örneğin bir bağlantıyı açmayı) engeller, ancak olayın DOM üzerinde yukarı doğru yayılmasını durdurmaz.

event.stopPropagation()
Olayın DOM içinde yukarı doğru yayılmasını engeller, ancak tarayıcının varsayılan davranışını durdurmaz.

return false;
Genellikle jQuery kodunda görülen bu ifade, tarayıcının varsayılan davranışını engeller, olayın DOM üzerinde yukarı doğru yayılmasını önler ve herhangi bir geri çağırmadan hemen değer döndürür.

Yukarıdaki parçanın alındığı yerden örneklerle birlikte bu gerçekten güzel ve kolay 4 dakikalık okumaya göz atın.

İlgili makaleler