Quelle est la différence entre event.stopPropagation et event.preventDefault?

835

Ils semblent faire la même chose ...
Est-ce un moderne et un vieux? Ou sont-ils pris en charge par différents navigateurs?

Lorsque je gère les événements moi-même (sans framework), je vérifie toujours les deux et les exécute s'ils sont présents. (Moi aussi return false, mais j'ai le sentiment que cela ne fonctionne pas avec les événements liés node.addEventListener).

Alors pourquoi les deux? Dois-je continuer à vérifier les deux? Ou y a-t-il réellement une différence?

(Je sais, beaucoup de questions, mais ce sont toutes les mêmes =))

Rudie
la source

Réponses:

1016

stopPropagation empêche l'événement de se propager dans la chaîne d'événements.

preventDefault empêche l'action par défaut du navigateur sur cet événement.

Exemples

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>

Avec stopPropagation, seul le buttongestionnaire de clic de est appelé tandis que le divgestionnaire de clic de ne se déclenche jamais.

Où, comme si vous l'utilisiez preventDefault, seule l'action par défaut du navigateur est arrêtée mais le gestionnaire de clics de la div se déclenche toujours.

Voici quelques documents sur les propriétés et méthodes des événements DOM de MDN:

Pour IE9 et FF, vous pouvez simplement utiliser preventDefault & stopPropagation.

Pour prendre en charge IE8 et inférieur remplacer stopPropagationpar cancelBubbleet remplacer preventDefaultparreturnValue

Raynos
la source
Ils sont donc très différents? IE a-t-il également deux méthodes d'événement différentes pour cela? (Pourraient - ils être le même ??) Il est étrange que les cadres faire les deux dans leur event.stopfonction ... Aussi bizarre que je ne l' ai jamais eu du mal avec ça. J'utilise beaucoup le bouillonnement. Merci pour l'exemple!
Rudie
@Rudie a commenté la prise en charge du navigateur.
Raynos
7
Il convient de noter (dans le cas où vous ne regardez pas le MSDN docs) qui cancelBubbleet returnValuesont les deux propriétés (devrait donc être ensemble cancelBubble = true;), et que preventDefaultet stopPropagationsont des méthodes (donc devraient être appelés preventDefault();)
freefaller
1
@Raynos, juste une note: event.stopPropagation () empêche non seulement l'événement de se propager dans la chaîne d'événements, mais également la propagation d'événements dans la phase de capture ( developer.mozilla.org/en-US/docs/Web/ API / Event / stopPropagation )
Yuci
1
Il serait utile de savoir quelle est l'action par défaut pour un clic sur un bouton afin que je puisse comprendre pourquoi stopDefault()ne fonctionne pas de la même manière que stopPropagation(). Si l'action par défaut n'appelle pas la onclickméthode, c'est quoi?
d512
249

Terminologie

De quirksmode.org :

Capture d'événement

Lorsque vous utilisez la capture d'événements

               | |
--------------- | | -----------------
| element1 | | |
| ----------- | | ----------- |
| | element2 \ / | |
| ------------------------- |
| Événement CAPTURING |
-----------------------------------

le gestionnaire d'événements de element1 se déclenche en premier, le gestionnaire d'événements de element2 se déclenche en dernier.

Bulle d'événement

Lorsque vous utilisez le bouillonnement d'événements

               / \
--------------- | | -----------------
| element1 | | |
| ----------- | | ----------- |
| | element2 | | | |
| ------------------------- |
| Événement BUBBLING |
-----------------------------------

le gestionnaire d'événements de element2 se déclenche en premier, le gestionnaire d'événements de element1 se déclenche en dernier.

Tout événement se déroulant dans le modèle d'événement W3C est d'abord capturé jusqu'à ce qu'il atteigne l'élément cible, puis bouillonne à nouveau .

                 | | / \
----------------- | | - | | -----------------
| element1 | | | | |
| ------------- | | - | | ----------- |
| | element2 \ / | | | |
| -------------------------------- |
| Modèle d'événement W3C |
------------------------------------------

Interface

Depuis w3.org , pour la capture d'événements :

Si la capture EventListenersouhaite empêcher la poursuite du traitement de l'événement, elle peut appeler la stopPropagationméthode de l' Eventinterface. Cela empêchera la poursuite de l'envoi de l'événement, bien que d'autres personnes EventListenersenregistrées au même niveau de hiérarchie recevront toujours l'événement. Une fois la stopPropagation méthode d' un événement appelée, les appels ultérieurs à cette méthode n'ont aucun effet supplémentaire. Si aucun capturer supplémentaire n'existe et stopPropagationn'a pas été appelé, l'événement déclenche le approprié EventListenerssur la cible elle-même.

Pour le bouillonnement d'événement :

Tout gestionnaire d'événements peut choisir d'empêcher la propagation d'événements supplémentaires en appelant la stopPropagationméthode de l' Eventinterface. Si quelqu'un EventListenerappelle cette méthode, tous les éléments supplémentaires EventListenerssur le courant EventTargetseront déclenchés mais le bouillonnement cessera à ce niveau. Un seul appel à stopPropagationest requis pour empêcher de nouvelles bulles.

Pour l' annulation de l'événement :

Cancelation est accompli en appelant la Eventde » preventDefault méthode. Si un ou plusieurs EventListenersappels au preventDefaultcours d'une phase du flux d'événements, l'action par défaut sera annulée.

Exemples

Dans les exemples suivants, un clic sur l'hyperlien dans le navigateur Web déclenche le flux de l'événement (les écouteurs d'événements sont exécutés) et l'action par défaut de la cible de l'événement (un nouvel onglet est ouvert).

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

Exemple 1 : il en résulte la sortie

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

Exemple 2 : ajout stopPropagation()à la fonction

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

entraîne la sortie

DIV event capture

L'écouteur d'événement a empêché toute propagation vers le bas et vers le haut de l'événement. Cependant, cela n'a pas empêché l'action par défaut (une nouvelle ouverture d'onglet).

Exemple 3 : ajout stopPropagation()à la fonction

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

ou la fonction

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

entraîne la sortie

DIV event capture
A event capture
A event bubbling

En effet, les deux écouteurs d'événements sont enregistrés sur la même cible d'événement. Les écouteurs d'événement ont empêché la propagation vers le haut de l'événement. Cependant, ils n'ont pas empêché l'action par défaut (une nouvelle ouverture d'onglet).

Exemple 4 : ajout preventDefault()à n'importe quelle fonction, par exemple

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

empêche l'ouverture d'un nouvel onglet.

Ashkan
la source
23
Merci pour la distinction plus profonde entre la capture et le bouillonnement, tandis que l'autre réponse ne répond qu'aux préoccupations de jQuery.
floribon
@floribon dit que vous n'avez aucune intention d'offenser raynos pour sa réponse.
Mahi
3
@Mahi quoi? Je dis juste des faits, la réponse acceptée utilise jQuery qui n'est pas supposée par OP, donc pour moi ce n'est pas la vraie réponse. Maintenant, c'est juste un fait technique, rien de personnel et personne à offenser.
floribon
2
Votre réponse est très systématique et montre bien ce qui se passe. Au départ, je ne voulais pas vous déranger et apporter moi-même des modifications à votre réponse, car je pense qu'elle pourrait être un peu améliorée pour plus de clarté. Cette réponse explique le modèle d'événement aux débutants et en tant que tel, je pense que chaque aide que nous pouvons apporter aux débutants va très loin. Ma suggestion de modification a été refusée par des arguments génériques avec lesquels je ne suis pas d'accord. Si vous, @Ashkan, pensez que ces petits changements pourraient aider à améliorer la réponse, veuillez les incorporer.
mucaho
68

retour faux;


return false; fait 3 choses distinctes lorsque vous l'appelez:

  1. event.preventDefault() - Il arrête le comportement par défaut des navigateurs.
  2. event.stopPropagation() - Il empêche l'événement de propager (ou de «bouillonner») le DOM.
  3. Arrête l'exécution du rappel et retourne immédiatement lorsqu'il est appelé.

Notez que ce comportement diffère des gestionnaires d'événements normaux (non jQuery), dans lesquels, notamment, return falsen'empêche pas l'événement de se propager.

preventDefault ();


preventDefault(); fait une chose: il arrête le comportement par défaut des navigateurs.

Quand les utiliser?


Nous savons ce qu'ils font mais quand les utiliser? Cela dépend simplement de ce que vous voulez accomplir. Utilisez-le preventDefault();si vous voulez "juste" empêcher le comportement du navigateur par défaut. Utilisez return false; lorsque vous souhaitez empêcher le comportement du navigateur par défaut et empêcher l'événement de propager le DOM. Dans la plupart des situations où vous utiliseriez return false; ce que vous voulez vraiment preventDefault().

Exemples:


Essayons de comprendre avec des exemples:

Nous verrons l'exemple pur JAVASCRIPT

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

Exécutez le code ci-dessus, vous verrez l'hyperlien «Cliquez ici pour visiter stackoverflow.com» maintenant si vous cliquez d'abord sur ce lien, vous obtiendrez l'alerte javascript Lien cliqué Ensuite, vous obtiendrez l'alerte javascript div cliqué et immédiatement vous serez redirigé vers stackoverflow.com.

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

Exécutez le code ci-dessus, vous verrez l'hyperlien «Cliquez ici pour visiter stackoverflow.com» maintenant si vous cliquez d'abord sur ce lien, vous obtiendrez l'alerte javascript Lien cliqué sur Suivant, vous obtiendrez l'alerte javascript div . Cliquez ici pour visiter stackoverflow.com 'remplacé par le texte' Evénement clic empêché 'et vous ne serez pas redirigé vers stackoverflow.com. Cela est dû à la méthode event.preventDefault () que nous avons utilisée pour empêcher le déclenchement de l'action de clic par défaut.

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

Cette fois, si vous cliquez sur Lien, la fonction executeParent () ne sera pas appelée et vous n'obtiendrez pas l'alerte javascript div. Cliqué cette fois. Cela est dû au fait que nous avons empêché la propagation vers le div parent en utilisant la méthode event.stopPropagation (). Ensuite, vous verrez l'hyperlien «Cliquez ici pour visiter stackoverflow.com» remplacé par le texte «L'événement Click va être exécuté» et vous serez immédiatement redirigé vers stackoverflow.com. En effet, nous n'avons pas empêché l'action de clic par défaut de se déclencher cette fois à l'aide de la méthode event.preventDefault ().

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

Si vous cliquez sur le lien, la fonction executeParent () ne sera pas appelée et vous n'obtiendrez pas l'alerte javascript. Cela est dû au fait que nous avons empêché la propagation vers le div parent en utilisant la méthode event.stopPropagation (). Ensuite, vous verrez l'hyperlien «Cliquez ici pour visiter stackoverflow.com» remplacé par le texte «Événement de clic empêché» et vous ne serez pas redirigé vers stackoverflow.com. En effet, nous avons empêché l'action de clic par défaut de se déclencher cette fois en utilisant la méthode event.preventDefault ().

Exemple 5:

Pour le retour faux, j'ai trois exemples et tous semblent faire exactement la même chose (juste retourner faux), mais en réalité les résultats sont assez différents. Voici ce qui se passe réellement dans chacun des éléments ci-dessus.

cas:

  1. Renvoyer false depuis un gestionnaire d'événements en ligne empêche le navigateur de naviguer vers l'adresse du lien, mais cela n'empêche pas l'événement de se propager via le DOM.
  2. Renvoyer false depuis un gestionnaire d'événements jQuery empêche le navigateur de naviguer vers l'adresse du lien et empêche l'événement de se propager via le DOM.
  3. Renvoyer false depuis un gestionnaire d'événements DOM normal ne fait absolument rien.

Voir les trois exemples.

  1. Retour en ligne faux.

<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. Renvoyer false depuis un gestionnaire d'événements 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. Renvoyer false depuis un gestionnaire d'événement DOM normal.

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

J'espère que ces exemples sont clairs. Essayez d'exécuter tous ces exemples dans un fichier html pour voir comment ils fonctionnent.

Keval Bhatt
la source
1
De bons exemples, mais cela aurait été encore mieux sans jQuery, car jQuery simule l'objet événement, c'est donc techniquement différent.
Rudie
1
@Rudie J'ai mis à jour ma réponse et en ai supprimé jquery, et j'ai également ajouté un exemple de retour faux.
Keval Bhatt
17

Ceci est la citation d' ici

Event.preventDefault

La méthode preventDefault empêche un événement d'exécuter sa fonctionnalité par défaut. Par exemple, vous utiliseriez preventDefault sur un élément A pour arrêter de cliquer sur cet élément de quitter la page actuelle:

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

Alors que la fonctionnalité par défaut de l'élément est maçonnée, l'événement continue de bouillonner le DOM.

Event.stopPropagation

La deuxième méthode, stopPropagation, permet à la fonctionnalité par défaut de l'événement de se produire mais empêche l'événement de se propager:

//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 empêche efficacement les éléments parents de connaître un événement donné sur son enfant.

Alors qu'une méthode d'arrêt simple nous permet de gérer rapidement les événements, il est important de penser à ce que vous voulez exactement avec le bullage. Je parie que tout ce qu'un développeur veut vraiment, c'est de prévenir par défaut 90% du temps! Un "arrêt" incorrect d'un événement peut vous causer de nombreux problèmes sur toute la ligne; vos plugins peuvent ne pas fonctionner et vos plugins tiers peuvent être briqués. Ou pire encore - votre code rompt d'autres fonctionnalités sur un site.

VladL
la source
2

Event.preventDefault - arrête le comportement par défaut du navigateur. Voici maintenant quel est le comportement par défaut du navigateur. Supposons que vous ayez une balise d'ancrage et qu'elle ait un attribut href et que cette balise d'ancrage soit imbriquée dans une balise div qui a un événement click. Le comportement par défaut de la balise d'ancrage est lorsque vous cliquez sur la balise d'ancrage dans laquelle il doit naviguer, mais ce que fait event.preventDefault, c'est qu'il arrête la navigation dans ce cas. Mais cela n'arrête jamais le bouillonnement de l'événement ou l'escalade de l'événement, c'est-à-dire

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

Le résultat sera

"l'élément a été cliqué"

"le conteneur a été cliqué"

Maintenant event.StopPropation, il arrête la propagation de l'événement ou l'escalade de l'événement. Maintenant avec l'exemple ci-dessus

$('.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');
});

Le résultat sera

"l'élément a été cliqué"

Pour plus d'informations, reportez-vous à ce lien https://codeplanet.io/preventdefault-vs-stoppropagation-vs-stopimmediatepropagation/

Nayas Subramanian
la source
1

event.preventDefault(); Empêche l'action par défaut d'un élément de se produire.

event.stopPropagation(); Empêche l'événement de se propager dans l'arborescence DOM, empêchant les gestionnaires parents d'être notifiés de l'événement.

Par exemple, s'il y a un lien avec une méthode de clic à l' intérieur d'un joint DIVou FORMqui a également une méthode de clic ci - joint, il empêchera le DIVou FORMcliquez sur la méthode de mise à feu.

Mike Clark
la source
-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
la source