واگذاری رویداد
پشت باجه یک نوار بلیت است. اسمش #strip است. دو دکمه از قبل رویش نشستهاند: #red با متن red، و #blue با متن blue. زیر نوار، بند #note هنوز blank میگوید.
لازم نیست روی هر دکمه جدا گوش بدهی. یک بار addEventListener را روی خود نوار میگذاری. کلیک هر دکمهای که داخل نوار باشد بالا میآید و به همان تابع میرسد. event.target همان دکمه است. event.currentTarget خود نوار است، یعنی جایی که شنونده نشسته.
دکمهٔ #gold اول توی صفحه نیست. بعد از ثبت شنونده ساخته میشود، به نوار میچسبد، و روش کلیک میخورد. همان تابع باز هم اجرا میشود. بند میشود gold. اسکریپت اول red را میزند، بعد blue، بعد gold. addEventListener فقط یک بار صدا زده شده، پس hands برابر ۱ است. خط زیر نوار این است: 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 | خط پلاک، یا تمام شدن با ۳ |
کلیک روی دکمه یک رویداد است. target برای همهٔ شنوندههای سر راه همان دکمه میماند. اینجا فقط یک شنونده داریم و روی نوار است، پس تا وقتی تابع در حال اجراست currentTarget همان نوار است. کلیک به نوار میرسد چون کسی stopPropagation صدا نزده. صفحهٔ پلاک آن مسیر را میبرید. اینجا نه.
preventDefault برای کار پیشفرض مرورگر است، مثل رفتن یک لینک. اینها دکمه هستند، نه لینک. نیاوردن preventDefault یعنی همین صفحه کامل است، نه اینکه خطی جا افتاده باشد.
اگر event.target و event.currentTarget یک گره باشند، کلیک روی خود نوار نشسته، نه روی دکمه. تابع مینویسد skip و کاغذ را بلیت حساب نمیکند. seen.join(" / ") فقط شناسههایی را به هم میچسباند که قبلاً داخل seen رفتهاند. hands بعد از آن میآید. پس واژهٔ آخر تعداد دفعههای addEventListener است، نه تعداد کلیکها.
بلیتی که زیر کلیک است
شنونده روی نوار است. تابع پارامتر event دارد و event.target.id را در بند مینویسد. بعد صفحه روی red کلیک میکند. روی خود 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 است. وقتی addEventListener اجرا شد، gold هنوز نبود. کلیک از 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 میشود ۱. اول red کلیک میخورد، بعد blue. شناسهٔ هر بلیت داخل seen میرود. gold ساخته میشود، میچسبد، و کلیک میخورد، پس gold هم میرود داخل seen. خط بعد از همین کلیک سوم نوشته میشود. صفحه روی خود نوار کلیک نمیکند، برای همین 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 یک بار اجرا شده، پس آن واژه ۱ است، نه ۳. بند در پایان 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بهصورت ۲ - صدا زدن
preventDefaultیاstopPropagation؛ آن مال صفحهٔ پلاک بود - انتظار اینکه آرگومان تابع خود عنصر دکمه باشد
- خواندن خط به شکل click / seal / plaque / true / quiet، یا wool silk / 2 / peg
- خواندن واژهٔ آخر بهصورت ۳، چون سه بلیت کلیک خوردهاند
این را نگه دار
- یک
addEventListenerروی نوار، کلیک هر دکمهای داخلش را میشنود - با کلیک روی red، مقدار
event.target.idبرابر red است وevent.currentTarget.idبرابر strip - همان شنونده با کلیک روی blue مینویسد blue
- gold که بعد از شنونده ساخته شده باز هم gold مینویسد
- کلیک روی خود نوار، با نگهبان، مینویسد skip
- خط صفحه میشود red / blue / gold / 1
🧠 دانش خود را بیازمایید
دانش خود را بیازمایید
خود را با این آزمون تعاملی به چالش بکشید و ببینید موضوع را چقدر خوب درک کردهاید
📝 دستورالعملها
- هر سوال را با دقت بخوانید
- بهترین پاسخ را برای هر سوال انتخاب کنید
- میتوانید آزمون را هر چند بار که میخواهید تکرار کنید
- پیشرفت شما در بالا نمایش داده میشود