Vue: @click déclencherait un autre événement vnode @click.

Créé le 11 sept. 2017  ·  4Commentaires  ·  Source: vuejs/vue

Version

2.4.2

Lien de reproduction

https://jsbin.com/qejofexedo/edit?html , js, sortie

Étapes à suivre pour reproduire

voir le lien de reproduction.

Qu'attend-on?

Lorsque je clique sur Expand is True , alors expand devient false . Et seulement countA changé.

Que se passe-t-il réellement?

Lorsque je clique sur Expand is Ture , rien ne se passe.
Les countA et countB changé.
Je suppose que lorsque je clique, expand devient false , mais immédiatement l'événement de clic déclenché. Il exécute un autre événement de clic vnode. Ensuite, le développement devient true .

Et plus

  • Si je renomme le deuxième div en un autre nom de balise, tel que p , section , aucune erreur ne se produit.
  • Si je déplace l'événement de clic i balise div dans le premier div, aucune erreur ne se produit
bug improvement

Commentaire le plus utile

Donc, cela se produit parce que:

  • L'événement de clic interne sur <i> se déclenche, déclenchant une 1ère mise à jour sur nextTick (microtask)
  • La microtâche est traitée avant que l'événement ne se propage vers le div externe . Pendant la mise à jour, un écouteur de clic est ajouté à la div externe.
  • Comme la structure DOM est la même, le div externe et l'élément interne sont réutilisés.
  • L'événement atteint finalement la div externe, déclenche l'auditeur ajouté par la 1ère mise à jour, déclenchant à son tour une 2ème mise à jour.

C'est assez délicat dans le correctif, et d'autres bibliothèques qui utilisent la microtâche pour la mise en file d'attente des mises à jour ont également ce problème (par exemple Preact). React ne semble pas avoir ce problème car ils utilisent un système d'événements synthétiques (probablement à cause de cas extrêmes comme celui-ci).

Pour contourner ce problème, vous pouvez simplement attribuer des clés différentes aux deux div externes pour les forcer à être remplacées lors des mises à jour. Cela empêcherait l'événement de bulles d'être capté:

<div class="header" v-if="expand" key="1"> // block 1
  <i @click="expand = false, countA++">Expand is True</i> // element 1
</div>
<div class="expand" v-if="!expand" @click="expand = true, countB++" key="2"> // block 2
  <i>Expand is False</i> // element 2
</div>

Tous les 4 commentaires

qq20170911-185025
semble normal

Votre repro fonctionne comme prévu ...

@Kingwl @ yyx990803 Désolé pour ça. J'ai testé d'autres cas et j'ai oublié de revenir en arrière.

Le code important est

<div class="header" v-if="expand"> // block 1
  <i @click="expand = false, countA++">Expand is True</i> // element 1
</div>
<div class="expand" v-if="!expand" @click="expand = true, countB++"> // block 2
  <i>Expand is False</i> // element 2
</div>

Il y a quatre cas:

  • cliquez sur l'événement écouter sur block 1 et block2 , fonctionne bien
  • cliquez sur l'événement écouter sur element 1 et element 2 , fonctionne bien
  • cliquez sur l'événement écoutez sur block 1 et element 2 , changez expand en true c'est ok. Mais je ne peux pas revenir en arrière.
  • cliquez sur l'événement écouter sur element 1 et block 2 , impossible de changer expand en faux. Mais peut changer expand en vrai.

Donc, cela se produit parce que:

  • L'événement de clic interne sur <i> se déclenche, déclenchant une 1ère mise à jour sur nextTick (microtask)
  • La microtâche est traitée avant que l'événement ne se propage vers le div externe . Pendant la mise à jour, un écouteur de clic est ajouté à la div externe.
  • Comme la structure DOM est la même, le div externe et l'élément interne sont réutilisés.
  • L'événement atteint finalement la div externe, déclenche l'auditeur ajouté par la 1ère mise à jour, déclenchant à son tour une 2ème mise à jour.

C'est assez délicat dans le correctif, et d'autres bibliothèques qui utilisent la microtâche pour la mise en file d'attente des mises à jour ont également ce problème (par exemple Preact). React ne semble pas avoir ce problème car ils utilisent un système d'événements synthétiques (probablement à cause de cas extrêmes comme celui-ci).

Pour contourner ce problème, vous pouvez simplement attribuer des clés différentes aux deux div externes pour les forcer à être remplacées lors des mises à jour. Cela empêcherait l'événement de bulles d'être capté:

<div class="header" v-if="expand" key="1"> // block 1
  <i @click="expand = false, countA++">Expand is True</i> // element 1
</div>
<div class="expand" v-if="!expand" @click="expand = true, countB++" key="2"> // block 2
  <i>Expand is False</i> // element 2
</div>
Cette page vous a été utile?
0 / 5 - 0 notes