Vue: @clickは、他のvnode @ clickイベントのイベントをトリガーします。

作成日 2017年09月11日  ·  4コメント  ·  ソース: vuejs/vue

バージョン

2.4.2

複製リンク

https://jsbin.com/qejofexedo/edit?html、js、output

再現する手順

複製リンクを参照してください。

何が期待されますか?

Expand is Trueをクリックすると、 expandfalseます。 そして、 countA変更されました。

実際に何が起こっているのですか?

Expand is Tureをクリックしても、何も起こりませんでした。
countAcountB変更されました。
クリックすると、 expandfalseに変更されたと思いますが、すぐにクリックイベントがトリガーされます。 別のvnodeクリックイベントを実行します。 次に、展開をtrue変更しました。

もっと

  • 2番目のdivの名前をpsectionなどの別のタグ名に変更しても、エラーは発生しません。
  • 最初のdivでクリックイベントをiタグから親divタグに移動しても、エラーは発生しません
bug improvement

最も参考になるコメント

したがって、これは次の理由で発生します。

  • <i>の内部クリックイベントが発生し、nextTick(マイクロタスク)で最初の更新がトリガーされます
  • マイクロタスクは、イベントが外部divにバブルする前に処理されます。 更新中に、クリックリスナーが外部divに追加されます。
  • DOM構造が同じであるため、外側のdivと内側の要素の両方が再利用されます。
  • イベントは最終的に外部divに到達し、最初の更新によって追加されたリスナーをトリガーし、次に2番目の更新をトリガーします。

これは修正が非常に難しいため、更新キューイングにマイクロタスクを利用する他のライブラリにもこの問題があります(例:Preact)。 Reactは合成イベントシステムを使用しているため(おそらくこのようなエッジケースが原因)、この問題は発生していないようです。

これを回避するには、2つの外側のdivに異なるキーを指定して、更新中にそれらを強制的に置き換えることができます。 これにより、バブルイベントが取得されなくなります。

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

全てのコメント4件

qq20170911-185025
正常なようです

あなたの再現は意図したとおりに機能しています...

@Kingwl @ yyx990803ごめんなさい。 私は他のケースをテストし、元に戻すのを忘れました。

重要なコードは

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

4つのケースがあります:

  • block 1block2でクリックイベントをリッスンし、うまく機能します
  • クリックイベントはelement 1element 2でリッスンし、うまく機能します
  • block 1element 2でイベントリッスンをクリックし、 expandをtrueに変更しても問題ありません。 ただし、元に戻すことはできません。
  • element 1block 2でイベントリッスンをクリックします。 expandをfalseに変更することはできません。 ただし、 expandをtrueに変更できます。

したがって、これは次の理由で発生します。

  • <i>の内部クリックイベントが発生し、nextTick(マイクロタスク)で最初の更新がトリガーされます
  • マイクロタスクは、イベントが外部divにバブルする前に処理されます。 更新中に、クリックリスナーが外部divに追加されます。
  • DOM構造が同じであるため、外側のdivと内側の要素の両方が再利用されます。
  • イベントは最終的に外部divに到達し、最初の更新によって追加されたリスナーをトリガーし、次に2番目の更新をトリガーします。

これは修正が非常に難しいため、更新キューイングにマイクロタスクを利用する他のライブラリにもこの問題があります(例:Preact)。 Reactは合成イベントシステムを使用しているため(おそらくこのようなエッジケースが原因)、この問題は発生していないようです。

これを回避するには、2つの外側のdivに異なるキーを指定して、更新中にそれらを強制的に置き換えることができます。 これにより、バブルイベントが取得されなくなります。

<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>
このページは役に立ちましたか?
0 / 5 - 0 評価