في هذا الدرس 5تصفّح المواضيع
عندما تنقر على عنصر <button> موضوع داخل بند <li> داخل قائمة <ul> داخل جسم الصفحة <body>، فأنت عملياً تنقر فوق هذه الحاويات المتداخلة جميعاً في اللحظة نفسها! ولذلك لا يطلق المتصفح الحدث بمعزل عن محيطه، بل يسيره في رحلة رأسية منظمة عبر شجرة DOM تُعرف باسم انتشار الحدث (Event Propagation).
استيعاب هذه الرحلة يمنحك أقوى أنماط هندسة الواجهات كفاءةً ونظافةً على الإطلاق وهو تفويض الأحداث (Event Delegation).
يقسم المعيار القياسي رحلة الحدث إلى ثلاثة أطوار متتابعة يمكن قراءة رقمها عبر الخاصية e.eventPhase:
| رقم واسم الطور | اتجاه الحركة بالشجرة | متى يعمل المستمع في هذا الطور؟ |
|---|---|---|
1 — طور الالتقاط (Capturing) | تنازلياً من window عبر الآباء نحو الهدف | فقط عند تفعيل الخيار { capture: true } |
2 — طور الهدف (Target) | لحظة الوصول للعنصر المنقور e.target | تعمل المستمعات المسجلة على العنصر الهدف نفسه |
3 — طور الفقاعة (Bubbling) | تصاعدياً من الأب حتى document وwindow | الوضع الافتراضي لجميع مستمعات addEventListener |
أثناء صعود الحدث في طور الفقاعة عبر الآباء، تمنحك خاصيتان في كائن الحدث الصورة الدقيقة الكاملة:
- الخاصية
e.target: تظل ثابتة لا تتغير طوال الرحلة، وتشير دائماً إلى أعمق عنصر داخلي وقع عليه النقر الفعلي في البداية. - الخاصية
e.currentTarget: تشير في كل محطة إلى العنصر الأب الحامل للمستمع الذي يجري تنفيذه الآن.
تخيل بطاقة قابلة للنقر لفتح تفاصيل المنتج وبداخلها زر صغير «حذف»؛ عند نقر الحذف لا نريد أن يتفعل مستمع النقر على البطاقة الخارجية معها. هنا يستدعى e.stopPropagation() داخل زر الحذف ليوقف صعود الحدث نحو العناصر الأب.
انتبه لعدم الخلط بين e.stopPropagation() التي تمنع وصول الحدث للآباء وبين e.preventDefault() التي تلغي سلوك المتصفح الافتراضي؛ وتجنب الإفراط العشوائي في إيقاف الانتشار لأن إغلاق القوائم المنسدلة عند النقر خارجها يعتمد على وصول الفقاعة إلى document.
const card = document.getElementById('course-card');
const muteBtn = document.getElementById('mute-btn');
const log = document.getElementById('prop-log');
card.addEventListener('click', function () {
log.textContent = 'Opened full course card!';
});
muteBtn.addEventListener('click', function (e) {
e.stopPropagation();
log.textContent = 'Muted alert only (card skipped).';
});
لنفترض وجود قائمة مهام تضم 200 عنصر مع زر يضيف عناصر <li> جديدة ديناميكياً؛ ربط 200 مستمع منفصل يستهلك الذاكرة ولا يشمل العناصر المضافة لاحقاً تلقائياً. يحل نمط تفويض الأحداث هذه المعضلة بوضع مستمع واحد فقط على القائمة الأب <ul> استناداً لطور الفقاعة!
وداخل مستمع الأب نستدعي e.target.closest("button.del-btn") للعثور بدقة وأمان على زر الإجراء المقصود (حتى لو نقر الزائر على نص فرعي بداخل الزر) فيعمل فوراً مع العناصر الحالية والمستقبلية.
let id = 3;
const list = document.getElementById('task-list');
document.getElementById('add-task').onclick = function () {
const li = document.createElement('li');
li.innerHTML = 'Task #' + (id++) +
' <button type="button" class="del">Remove</button>';
list.appendChild(li);
};
list.addEventListener('click', function (e) {
const btn = e.target.closest('button.del');
if (btn && list.contains(btn)) btn.closest('li').remove();
});
ملخص الدرس
حصاد الدرسمراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي
ماذا تعلّمت في هذا الدرس؟
اختتمت الفصل العاشر بإتقان أطوار انتشار الحدث الثلاثة (الالتقاط والهدف والفقاعة)، والتمييز بين e.target وe.currentTarget، وضبط الصعود عبر e.stopPropagation()، وتطبيق نمط تفويض الأحداث الذكي مع closest(). الخطوة التالية: ابدأ الفصل الحادي عشر بدرس «التنقل داخل شجرة DOM» لاستكشاف علاقات الآباء والأبناء والأشقاء.
سجّل الدخول لحفظ تقدمك
تابع إنجاز المواضيع والمصطلحات والمهام، وكمّل من آخر خطوة على أي جهاز.
المصطلحات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 Event Bubbling طور الفقاعة الصاعد Bubbling
- الطور الثالث الافتراضي لانتشار الحدث حيث يصعد من العنصر الهدف عبر آبائه المتتاليين حتى أعلى المستند.
- للمراجعة
- 02 Event Capturing طور الالتقاط التنازلي Capturing
- الطور الأول لانتشار الحدث حيث ينزل من النافذة عبر الآباء وصولاً إلى العنصر الهدف عند تفعيل capture.
- للمراجعة
- 03 event.stopPropagation() دالة إيقاف الانتشار stopPropagation
- تمنع الحدث الحالي من مواصلة الانتقال إلى مستمعات العناصر الأب دون إلغاء السلوك الافتراضي للمتصفح.
- للمراجعة
- 04 Event Delegation نمط تفويض الأحداث Event Delegation
- ربط مستمع واحد بالحاوية الأب لمعالجة أحداث كافة العناصر الفرعية الحالية والمضافة ديناميكياً بفضل الفقاعة.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
الاختصارات2
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 DOM DOM
- Document Object Model
- البنية الشجرية الهرمية التي تسلكها إشارات الأحداث نزولاً وصعوداً بين العناصر.
- للمراجعة
- 02 RAM RAM
- Random Access Memory
- ذاكرة الجهاز التي يوفرها نمط تفويض الأحداث باستبدال مئات المستمعات بمستمع أب واحد.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
مهامك قبل الاختبار
خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.
-
انقر جسم البطاقة الخارجي في المحرر ثم انقر الزر الداخلي للتأكد من أن stopPropagation تمنع تشغيل مستمع البطاقة.
-
أضف مهمتين جديدتين في مثال التفويض ثم احذفهما لتشهد كيف يتعامل مستمع القائمة الأب الواحد مع العناصر الجديدة فوراً.
تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.
اختبر فهمك.
ووصلها للإتقان.
كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.
أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.
الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.