Vue: @click würde ein anderes vnode @click-Ereignis auslösen.

Erstellt am 11. Sept. 2017  ·  4Kommentare  ·  Quelle: vuejs/vue

Ausführung

2.4.2

Reproduktionslink

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

Schritte zum Reproduzieren

siehe Reproduktionslink.

Was wird erwartet?

Wenn ich auf Expand is True , dann auf expand , um false . Und nur countA geändert.

Was passiert eigentlich?

Wenn ich auf Expand is Ture , ist nichts passiert.
Die countA und countB geändert.
Ich denke, wenn ich klicke, ändert sich expand in false , aber sofort wird das Klickereignis ausgelöst. Es führt ein anderes vnode-Klickereignis aus. Erweitern Sie dann geändert in true .

Und mehr

  • Wenn ich das zweite Div in einen anderen Tag-Namen umbenenne, z. B. p , section , treten keine Fehler auf.
  • Wenn ich das Klickereignis vom i -Tag zum übergeordneten div -Tag im ersten Div verschiebe, treten keine Fehler auf
bug improvement

Hilfreichster Kommentar

Das passiert also, weil:

  • Das innere Klickereignis auf <i> wird ausgelöst und löst ein erstes Update bei nextTick (Mikrotask) aus.
  • Die Mikrotask wird verarbeitet, bevor das Ereignis zum äußeren Teil sprudelt . Während des Updates wird dem äußeren Div ein Klick-Listener hinzugefügt.
  • Da die DOM-Struktur identisch ist, werden sowohl das äußere div als auch das innere Element wiederverwendet.
  • Das Ereignis erreicht schließlich das äußere Div, löst den durch das 1. Update hinzugefügten Listener aus und löst wiederum ein 2. Update aus.

Dies ist in der Korrektur ziemlich schwierig, und andere Bibliotheken, die Mikrotask für die Aktualisierungswarteschlange nutzen, haben ebenfalls dieses Problem (z. B. Preact). React scheint dieses Problem nicht zu haben, da sie ein synthetisches Ereignissystem verwenden (wahrscheinlich aufgrund solcher Randfälle).

Um dies zu umgehen, können Sie den beiden äußeren Divs einfach unterschiedliche Schlüssel geben, damit sie bei Aktualisierungen ersetzt werden. Dies würde verhindern, dass das sprudelnde Ereignis erfasst wird:

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

Alle 4 Kommentare

qq20170911-185025
scheint normal

Ihr Repro funktioniert wie vorgesehen ...

@Kingwl @ yyx990803 Entschuldigung. Ich teste den Fall anderer und habe vergessen, mich zurückzuziehen.

Der wichtige Code ist

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

Es gibt vier Fälle:

  • Klicken Sie auf Event Listen auf block 1 und block2 , funktioniert gut
  • Klicken Sie auf Event Listen auf element 1 und element 2 , funktioniert gut
  • Klicken Sie auf Ereignis. Hören Sie auf block 1 und element 2 . Ändern Sie expand in true. Kann sich aber nicht zurück ändern.
  • Klicken Sie auf Ereignis. Hören Sie auf element 1 und block 2 . expand kann nicht in false geändert werden. Kann aber expand in true ändern.

Das passiert also, weil:

  • Das innere Klickereignis auf <i> wird ausgelöst und löst ein erstes Update bei nextTick (Mikrotask) aus.
  • Die Mikrotask wird verarbeitet, bevor das Ereignis zum äußeren Teil sprudelt . Während des Updates wird dem äußeren Div ein Klick-Listener hinzugefügt.
  • Da die DOM-Struktur identisch ist, werden sowohl das äußere div als auch das innere Element wiederverwendet.
  • Das Ereignis erreicht schließlich das äußere Div, löst den durch das 1. Update hinzugefügten Listener aus und löst wiederum ein 2. Update aus.

Dies ist in der Korrektur ziemlich schwierig, und andere Bibliotheken, die Mikrotask für die Aktualisierungswarteschlange nutzen, haben ebenfalls dieses Problem (z. B. Preact). React scheint dieses Problem nicht zu haben, da sie ein synthetisches Ereignissystem verwenden (wahrscheinlich aufgrund solcher Randfälle).

Um dies zu umgehen, können Sie den beiden äußeren Divs einfach unterschiedliche Schlüssel geben, damit sie bei Aktualisierungen ersetzt werden. Dies würde verhindern, dass das sprudelnde Ereignis erfasst wird:

<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>
War diese Seite hilfreich?
0 / 5 - 0 Bewertungen