تفويض الأحداث
في شباك التذاكر شريط واحد. الأب هو #strip. عليه زرّان من البداية: #red ونصّه red، و#blue ونصّه blue. تحت الشريط تقول #note كلمة blank.
لا تضع مستمعًا على كل زر. استدعِ addEventListener مرة على الشريط نفسه. نقرة أي زر داخل الشريط تصعد إلى الدالة نفسها. event.target هو الزر. event.currentTarget هو الشريط، أي العنصر الذي يجلس عليه هذا المستمع.
زر #gold ليس في الصفحة بعد. يُنشأ بعد حفظ المستمع، ثم يُلحق بالشريط ويُنقر. الدالة نفسها تعمل. الورقة تصير gold. السكربت ينقر red ثم blue ثم gold. addEventListener نُودي مرة واحدة، فصار hands يساوي 1. السطر تحت الشريط: red / blue / gold / 1. هذه الأزرار type="button". هنا لا ننادي preventDefault ولا stopPropagation. ذلك كان في صفحة اللوحة، وهناك لم يُضف ابن بعد المستمع.
مستمع واحد لكل التذاكر
صفحة اللوحة سمّت event وقرأت type وtarget وcurrentTarget على رابط داخل جدار. سطرها كان click / seal / plaque / true / quiet. علاقة المعطف خزّنت wool وsilk بلا وسيط. سطرها كان wool silk / 2 / peg. هنا يبقى الوسيط event، لكن عمل target مختلف: يخبرك أي ابن نُقر، حتى لو لم يكن موجودًا بعد.
getElementById يعطيك الشريط وزر الأحمر وزر الأزرق والورقة فقط. يولد gold من createElement. مستمع على red وآخر على blue يفوّتان gold إلا إذا ألصقت مرة ثانية بعد appendChild. مستمع واحد على الشريط لا يحتاج تلك اللصقة الثانية. اقرأ currentTarget داخل الدالة. بعد رجوع الدالة تصير هذه الخاصية null.
ماذا يسجّل الشريط
تبدأ الورقة بكلمة blank. تبقى نصوص الأزرار red وblue، ويأتي gold لاحقًا. اقرأ الصفوف بالترتيب. كل قطعة تبدأ من شريط الزرّين، إلا صف الصفحة فهو العرض في الأسفل. ذلك العرض ينادي addEventListener مرة واحدة.
📊 ماذا يسجّل الشريط
| اللحظة | ماذا تقرأ | نص الورقة | الخلط السهل |
|---|---|---|---|
| مستمع على الشريط، نقر red | event.target.id |
red | قراءة currentTarget وهو strip |
| النقرة نفسها، قراءة currentTarget | event.currentTarget.id |
strip | قراءة معرّف التذكرة |
| المستمع نفسه، نقر blue | event.target.id |
blue | وضع مستمع خاص على blue |
| إنشاء gold بعد المستمع ثم نقره | event.target.id |
gold | ظن أن الزر الجديد صامت |
| نقر الشريط نفسه، مع الحارس | الورقة | skip | كتابة المعرّف strip |
| سكربت الصفحة | السطر | red / blue / gold / 1 | سطر اللوحة، أو رمز أخير 3 |
نقرة الزر حدث واحد. يبقى target ذلك الزر عند كل مستمع على الطريق. هنا مستمع واحد وعلى الشريط، فطوال تنفيذ الدالة يكون currentTarget هو الشريط. تصل النقرة إلى الشريط لأن أحدًا لا ينادي stopPropagation. صفحة اللوحة قطعت ذلك الطريق. هذه الصفحة لا تقطعه.
preventDefault لفعل المتصفح الافتراضي، مثل مغادرة رابط للصفحة. هذه عناصر أزرار لا روابط. غياب preventDefault هو الصفحة كاملة، لا سطرًا ناقصًا.
إذا كان event.target وevent.currentTarget العقدة نفسها، فقد نزلت النقرة على الشريط لا على زر. تكتب الدالة skip ولا تحسب الورق تذكرة. seen.join(" / ") يجمع المعرّفات التي دُفعت أصلًا. يأتي hands بعد ذلك. فالرمز الأخير هو عدد مرات نداء addEventListener، لا عدد النقرات.
التذكرة تحت النقرة
المستمع على الشريط. الدالة تسمّي الوسيط event وتكتب event.target.id في الورقة. ثم تنقر الصفحة red. لا تنادي addEventListener على red.
let strip = document.getElementById("strip");
let note = document.getElementById("note");
function take(event) {
note.textContent = event.target.id;
}
strip.addEventListener("click", take);
document.getElementById("red").click();
console.log(note.textContent);
الناتج red. عنصر المستمع هو الشريط. target لا يبلّغ عن الأب. يبلّغ عن الزر الذي تحت النقرة.
صاحب المستمع
شريط جديد، المستمع نفسه، النقرة نفسها على red. تكتب الورقة المعرّفين: target أولًا ثم currentTarget.
let strip = document.getElementById("strip");
let note = document.getElementById("note");
function take(event) {
note.textContent = event.target.id + " " + event.currentTarget.id;
}
strip.addEventListener("click", take);
document.getElementById("red").click();
console.log(note.textContent);
الناتج red strip. الكلمة الأولى التذكرة. الكلمة الثانية العنصر الذي يملك هذا المستمع. لو وُضع المستمع على red نفسه ثم نُقر red، صار الناتج red red. هذه القراءة من الشريط، لذلك يختلف المعرّفان.
التذكرة التي كانت بجانبه
شريط جديد مرة أخرى. مستمع واحد، ما زال على الشريط فقط. هذه المرة النقرة على blue. كان blue في الوسوم من البداية. ليس له مستمع يخصّه.
let strip = document.getElementById("strip");
let note = document.getElementById("note");
function take(event) {
note.textContent = event.target.id;
}
strip.addEventListener("click", take);
document.getElementById("blue").click();
console.log(note.textContent);
الناتج blue. نداء واحد لـ addEventListener غطّى الزرّين اللذين كانا داخل الشريط. لم يحل blue محل red. ولم يحتج red إلى نداء ثان.
تذكرة تُطبع لاحقًا
يُحفظ المستمع أولًا. ثم تبني الصفحة زرًا، تضع معرّفه gold، وتضبط type على button، والنص على gold، وتلحقه بالشريط. بعد ذلك فقط تنقر gold.
let strip = document.getElementById("strip");
let note = document.getElementById("note");
function take(event) {
note.textContent = event.target.id;
}
strip.addEventListener("click", take);
let gold = document.createElement("button");
gold.id = "gold";
gold.type = "button";
gold.textContent = "gold";
strip.appendChild(gold);
gold.click();
console.log(note.textContent);
الناتج gold. لم يكن gold موجودًا حين عمل addEventListener. النقرة تصعد من gold إلى الشريط، وtarget هو gold. لا تلصق مستمعًا على gold.
نقرة على الورق
الشريط نفسه عقدة قابلة للنقر. إذا كان target النقرة هو الشريط، فلا معرّف تذكرة يُحفظ. تقارن الدالة target مع currentTarget. إن تطابقا صارت الورقة skip.
let strip = document.getElementById("strip");
let note = document.getElementById("note");
function take(event) {
if (event.target === event.currentTarget) {
note.textContent = "skip";
return;
}
note.textContent = event.target.id;
}
strip.addEventListener("click", take);
strip.click();
console.log(note.textContent);
الناتج skip. كل من target وcurrentTarget هو الشريط، فيرفض الحارس الورق. نقرة red ما زالت تكتب red، لأن المرجعين مختلفان. احذف الحارس ويكتب strip.click() المعرّف strip في الورقة.
السطر تحت الشريط
السكربت في آخر body، بعد وجود الشريط والفقرتين. يُحفظ مستمع واحد ويصير hands القيمة 1. يُنقر red ثم blue. يُدفع معرّف كل تذكرة إلى seen. يُنشأ gold ويُلحق ويُنقر، فيُدفع gold أيضًا. يُكتب السطر بعد هذه النقرة الثالثة. الصفحة لا تنقر الشريط نفسه، لذلك ليس skip في السطر.
<!DOCTYPE html>
<html>
<head>
<title>event-delegation — page</title>
</head>
<body>
<div id="strip">
<button id="red" type="button">red</button>
<button id="blue" type="button">blue</button>
</div>
<p id="note">blank</p>
<p id="line">…</p>
<script>
let strip = document.getElementById("strip");
let note = document.getElementById("note");
let seen = [];
let hands = 0;
function take(event) {
if (event.target === event.currentTarget) {
note.textContent = "skip";
return;
}
note.textContent = event.target.id;
seen.push(event.target.id);
}
strip.addEventListener("click", take);
hands = hands + 1;
document.getElementById("red").click();
document.getElementById("blue").click();
let gold = document.createElement("button");
gold.id = "gold";
gold.type = "button";
gold.textContent = "gold";
strip.appendChild(gold);
gold.click();
document.getElementById("line").textContent =
seen.join(" / ") + " / " + hands;
</script>
</body>
</html>
يُقرأ السطر red / blue / gold / 1. المعرّفات الثلاثة هي التذاكر التي نُقرت، بالترتيب. الرمز الأخير هو hands. عمل addEventListener مرة، لذلك الرمز 1 لا 3. تنتهي الورقة عند gold لأن آخر نقرة كانت gold. ذهبت كلمة blank. لا تظهر كلمة skip. سطر اللوحة وسطر العلاقة صفحتان أخريان.
زر يحمل نصًا فقط يُبقي event.target على الزر، فيصير id هو red أو blue أو gold. ضع span داخل الزر وقد تنزل النقرة على span. ليس لـ span معرّف. هذه الصفحة لا تفعل ذلك.
عند الشباك
- ضع مستمعًا واحدًا على الشريط وانقر red. الورقة red. ليس لـ red مستمع يخصّه.
- بالمستمع نفسه انقر blue. الورقة blue.
- أنشئ gold وألحقه وانقره. الورقة gold. كان المستمع على الشريط من قبل.
- انقر الشريط نفسه. مع الحارس تصير الورقة skip. ثم اقرأ سطر الصفحة: red / blue / gold / 1.
ما يفوت عند الشباك
التسميات ما زالت تقول red وblue وgold. الورقة ليست كلمة تذكرة.
- مستمع على red وآخر على blue، ثم دهشة أن gold صامت
- قراءة
event.currentTargetحين أردت التذكرة - قراءة
event.targetحين أردت الشريط - نسيان الحارس، فيكتب
strip.click()القيمة strip spanداخل الزر، فيصيرtargetهو span ويبقى المعرّف فارغًا- نداء
addEventListenerمرة أخرى على gold، ثم عدّhandsكأنه 2 - نداء
preventDefaultأوstopPropagation؛ ذلك كان صفحة اللوحة - توقّع أن وسيط الدالة هو عنصر الزر
- قراءة السطر كأنه click / seal / plaque / true / quiet أو wool silk / 2 / peg
- قراءة الرمز الأخير كأنه 3 لأن ثلاث تذاكر نُقرت
ما يبقى معك
- نداء واحد لـ
addEventListenerعلى الشريط يسمع كل زر داخله - عند نقر red يكون
event.target.idهو red وevent.currentTarget.idهو strip - المستمع نفسه يكتب blue حين يُنقر blue
- gold، المُنشأ بعد المستمع، يكتب gold أيضًا
- نقرة على الشريط نفسه، مع الحارس، تكتب skip
- سطر الصفحة هو red / blue / gold / 1
🧠 اختبر معرفتك
اختبر معرفتك
تحدى نفسك مع هذا الاختبار التفاعلي واكتشف مدى فهمك للموضوع
📝 التعليمات
- اقرأ كل سؤال بعناية
- اختر أفضل إجابة لكل سؤال
- يمكنك إعادة الاختبار عدة مرات كما تريد
- سيتم عرض تقدمك في الأعلى