Vue: @click вызовет другое событие vnode @click.

Созданный на 11 сент. 2017  ·  4Комментарии  ·  Источник: vuejs/vue

Версия

2.4.2

Ссылка для воспроизведения

https://jsbin.com/qejofexedo/edit?html , js, вывод

Действия по воспроизведению

см. ссылку на воспроизведение.

Что ожидается?

Когда я нажимаю Expand is True , затем expand становится false . И изменилось только countA .

Что на самом деле происходит?

Когда я нажимаю Expand is Ture , ничего не происходит.
Значения countA и countB изменились.
Я предполагаю, что когда я нажимаю, expand меняется на false , но сразу запускается событие щелчка. Он выполняет еще одно событие щелчка vnode. Затем развернуть изменено на true .

И больше

  • Если я переименую второй div в другое имя тега, например p , section , ошибок не произойдет.
  • Если я перенесу событие клика из тега i в родительский тег div в первом div, ошибок не произойдет.
bug improvement

Самый полезный комментарий

Итак, это происходит потому, что:

  • Событие внутреннего щелчка на <i> запускается, вызывая 1-е обновление на nextTick (микрозадача)
  • Микрозадача обрабатывается до того, как событие перейдет во внешний div . Во время обновления к внешнему div добавляется прослушиватель кликов.
  • Поскольку структура DOM одинакова, повторно используются как внешний div, так и внутренний элемент.
  • Наконец, событие достигает внешнего div, запускает прослушиватель, добавленный 1-м обновлением, в свою очередь запускает 2-е обновление.

Это довольно сложно исправить, и другие библиотеки, которые используют микрозадачи для постановки в очередь обновлений, также имеют эту проблему (например, Preact). У React, похоже, нет этой проблемы, потому что они используют синтетическую систему событий (вероятно, из-за крайних случаев, подобных этому).

Чтобы обойти это, вы можете просто дать двум внешним 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>

Есть четыре случая:

  • прослушивание события щелчка на block 1 и block2 , работает хорошо
  • прослушивание события щелчка на element 1 и element 2 , работает хорошо
  • прослушивание события щелчка на block 1 и element 2 , изменение expand на true - это нормально. Но не может вернуться назад.
  • прослушивание событий щелчка на element 1 и block 2 , не может изменить expand на false. Но можно изменить expand на true.

Итак, это происходит потому, что:

  • Событие внутреннего щелчка на <i> запускается, вызывая 1-е обновление на nextTick (микрозадача)
  • Микрозадача обрабатывается до того, как событие перейдет во внешний div . Во время обновления к внешнему div добавляется прослушиватель кликов.
  • Поскольку структура DOM одинакова, повторно используются как внешний div, так и внутренний элемент.
  • Наконец, событие достигает внешнего div, запускает прослушиватель, добавленный 1-м обновлением, в свою очередь запускает 2-е обновление.

Это довольно сложно исправить, и другие библиотеки, которые используют микрозадачи для постановки в очередь обновлений, также имеют эту проблему (например, Preact). У React, похоже, нет этой проблемы, потому что они используют синтетическую систему событий (вероятно, из-за крайних случаев, подобных этому).

Чтобы обойти это, вы можете просто дать двум внешним 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 рейтинги