انتقل إلى محتوى الدرس
الدرس 68
دورة جافا سكريبت

انتشار وتفويض الأحداث في JavaScriptJavaScript Event Propagation and Delegation

أتقن انتشار وتفويض الأحداث في JavaScript: افهم أطوار الالتقاط والهدف والفقاعة، وميّز بين target وcurrentTarget، وطبق نمط التفويض الذكي عبر closest().
أقسام الدرس
5
الأمثلة
2
اللغة
العربية
تاريخ النشر
غير محدد
المشاهدات
7
محتوى الدرس
في هذا الدرس 5تصفّح المواضيع

عندما تنقر على عنصر <button> موضوع داخل بند <li> داخل قائمة <ul> داخل جسم الصفحة <body>، فأنت عملياً تنقر فوق هذه الحاويات المتداخلة جميعاً في اللحظة نفسها! ولذلك لا يطلق المتصفح الحدث بمعزل عن محيطه، بل يسيره في رحلة رأسية منظمة عبر شجرة DOM تُعرف باسم انتشار الحدث (Event Propagation).

استيعاب هذه الرحلة يمنحك أقوى أنماط هندسة الواجهات كفاءةً ونظافةً على الإطلاق وهو تفويض الأحداث (Event Delegation).

مخطط أطوار انتشار الحدث الثلاثة (الالتقاط والهدف والفقاعة) ونمط تفويض الأحداث عبر دالة closest

يقسم المعيار القياسي رحلة الحدث إلى ثلاثة أطوار متتابعة يمكن قراءة رقمها عبر الخاصية 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.

JavaScript
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") للعثور بدقة وأمان على زر الإجراء المقصود (حتى لو نقر الزائر على نص فرعي بداخل الزر) فيعمل فوراً مع العناصر الحالية والمستقبلية.

JavaScript
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

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 4 مفهومةأول بطاقة، أول خطوة
01 Event Bubbling طور الفقاعة الصاعد Bubbling
الطور الثالث الافتراضي لانتشار الحدث حيث يصعد من العنصر الهدف عبر آبائه المتتاليين حتى أعلى المستند.
للمراجعة
02 Event Capturing طور الالتقاط التنازلي Capturing
الطور الأول لانتشار الحدث حيث ينزل من النافذة عبر الآباء وصولاً إلى العنصر الهدف عند تفعيل capture.
للمراجعة
03 event.stopPropagation() دالة إيقاف الانتشار stopPropagation
تمنع الحدث الحالي من مواصلة الانتقال إلى مستمعات العناصر الأب دون إلغاء السلوك الافتراضي للمتصفح.
للمراجعة
04 Event Delegation نمط تفويض الأحداث Event Delegation
ربط مستمع واحد بالحاوية الأب لمعالجة أحداث كافة العناصر الفرعية الحالية والمضافة ديناميكياً بفضل الفقاعة.
للمراجعة

اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.

حروف قليلة. معنى كامل.

الاختصارات2

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 2 مفهومةأول بطاقة، أول خطوة
01 DOM DOM
Document Object Model
البنية الشجرية الهرمية التي تسلكها إشارات الأحداث نزولاً وصعوداً بين العناصر.
للمراجعة
02 RAM RAM
Random Access Memory
ذاكرة الجهاز التي يوفرها نمط تفويض الأحداث باستبدال مئات المستمعات بمستمع أب واحد.
للمراجعة

اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.

من الفهم للتطبيق

مهامك قبل الاختبار

خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.

0/2مهام منجزة
  1. انقر جسم البطاقة الخارجي في المحرر ثم انقر الزر الداخلي للتأكد من أن stopPropagation تمنع تشغيل مستمع البطاقة.

  2. أضف مهمتين جديدتين في مثال التفويض ثم احذفهما لتشهد كيف يتعامل مستمع القائمة الأب الواحد مع العناصر الجديدة فوراً.

تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.

مساحة التحدي

اختبر فهمك.
ووصلها للإتقان.

كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.

10أسئلة 2أنواع تحديات 100%هدف الإتقان
تصحيح تلقائي. فرص بلا حدود.

أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.

الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.

لمحة عن التحدي10 أسئلة تنتظرك
01

ما الترتيب الزمني الصحيح لأطوار انتشار الحدث الثلاثة في شجرة DOM؟

02

في أي طور يستمع الدالة element.addEventListener("click", handler) افتراضياً عند عدم تمرير خيار capture؟

03

عندما يصعد النقر من زر فرعي <button> إلى مستمع القائمة الأب <ul>، إلى ماذا يشير كل من e.target وe.currentTarget؟

04

ما الفرق الدقيق بين الدالتين e.stopPropagation() وe.preventDefault()؟

05

مستمع النقر الواحد المفوض على القائمة <ul> يعالج تلقائياً النقرات على عناصر <li> الجديدة المضافة ديناميكياً لاحقاً.

06

لماذا يُعد استخدام e.target.closest("button.del") أكثر أماناً من فحص e.target.tagName === "BUTTON" في تفويض الأحداث؟

07

الإفراط غير المبرر في استدعاء e.stopPropagation() قد يعطل مستمعات document المسؤولة عن إغلاق القوائم المنسدلة المفتوحة.

08

كيف تسجل مستمع حدث صراحةً ليعمل أثناء الطور الأول (طور الالتقاط التنازلي)؟

09

أي دالة توقف صعود الحدث للأب وتمنع في الوقت نفسه بقية المستمعات الشقيقة المسجلة على العنصر ذاته؟

10

جميع أحداث DOM بلا أي استثناء تصعد في طور الفقاعة بما فيها mouseenter وأحداث فشل الصور error.