Vue: click سيؤدي إلى حدث آخر vnodeclick.

تم إنشاؤها على ١١ سبتمبر ٢٠١٧  ·  4تعليقات  ·  مصدر: vuejs/vue

الإصدار

2.4.2

رابط الاستنساخ

https://jsbin.com/qejofexedo/edit؟html ، js، output

خطوات التكاثر

انظر ارتباط الاستنساخ.

ما هو متوقع؟

عندما أنقر على Expand is True ، ثم انقر على expand ليصبح false . وفقط countA تغيرت.

ما الذي يحدث بالفعل؟

عندما أنقر فوق Expand is Ture ، لم يحدث شيء.
تم تغيير countA و countB .
أعتقد أنه عند النقر ، تغير expand إلى false ، لكن حدث النقر على الفور بدأ. يقوم بتنفيذ حدث نقر vnode آخر. ثم قم بالتوسيع إلى true .

و اكثر

  • إذا أعدت تسمية div الثاني إلى اسم علامة آخر ، مثل p ، section ، فلن تحدث أخطاء.
  • إذا قمت بنقل حدث النقر من i tag إلى العلامة الأصل div tag في div الأول ، فلن تحدث أخطاء
bug improvement

التعليق الأكثر فائدة

لذلك ، يحدث هذا بسبب:

  • حرائق حدث النقر الداخلي في <i> ، مما أدى إلى بدء التحديث الأول في nextTick (مهمة صغيرة)
  • تتم معالجة المهمة الدقيقة قبل فقاعات الحدث إلى div الخارجي . أثناء التحديث ، تتم إضافة مستمع للنقرات إلى div الخارجي.
  • نظرًا لأن بنية DOM هي نفسها ، يتم إعادة استخدام كل من عنصر div الخارجي والعنصر الداخلي.
  • يصل الحدث أخيرًا إلى div الخارجي ، ويؤدي إلى تشغيل المستمع الذي تمت إضافته بواسطة التحديث الأول ، مما يؤدي بدوره إلى تشغيل التحديث الثاني.

يعد هذا أمرًا صعبًا للغاية في الإصلاح ، كما أن بعض العناصر الأخرى التي تستفيد من المهام الدقيقة في قائمة انتظار التحديث تواجه هذه المشكلة أيضًا (على سبيل المثال ، قبل التشغيل). لا يبدو أن 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
يبدو طبيعيا

يعمل repro الخاص بك على النحو المنشود ...

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> ، مما أدى إلى بدء التحديث الأول في nextTick (مهمة صغيرة)
  • تتم معالجة المهمة الدقيقة قبل فقاعات الحدث إلى div الخارجي . أثناء التحديث ، تتم إضافة مستمع للنقرات إلى div الخارجي.
  • نظرًا لأن بنية DOM هي نفسها ، يتم إعادة استخدام كل من عنصر div الخارجي والعنصر الداخلي.
  • يصل الحدث أخيرًا إلى div الخارجي ، ويؤدي إلى تشغيل المستمع الذي تمت إضافته بواسطة التحديث الأول ، مما يؤدي بدوره إلى تشغيل التحديث الثاني.

يعد هذا أمرًا صعبًا للغاية في الإصلاح ، كما أن بعض العناصر الأخرى التي تستفيد من المهام الدقيقة في قائمة انتظار التحديث تواجه هذه المشكلة أيضًا (على سبيل المثال ، قبل التشغيل). لا يبدو أن 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 التقييمات