Event Delegation: مدیریت هوشمند رویدادها با یک شنونده
تصور کنید یک لیست با صدها آیتم دارید و میخواهید با کلیک روی هر آیتم، یک عملیات مشخص اجرا شود. راه ساده اما ناکارآمد این است که برای تکتک آیتمها یک addEventListener جداگانه ثبت کنید. الگوی Event Delegation راهحلی بسیار بهتر ارائه میدهد: بهجای گوشدادن به هر عنصر بهصورت جداگانه، فقط روی عنصر والد مشترک یک شنونده ثبت میکنید و از رفتار Bubbling که در درس قبل بررسی شد، برای شناسایی عنصر واقعی که رویداد از آن آغاز شده استفاده میکنید.
چرا Event Delegation؟
ثبت شنونده برای هر عنصر بهصورت جداگانه دو مشکل اصلی دارد: مصرف حافظه بالا وقتی تعداد عناصر زیاد است، و ازکارافتادن شنونده برای عناصری که بعداً و بهصورت پویا به صفحه اضافه میشوند. Event Delegation هر دو مشکل را حل میکند، چون شنونده فقط یکبار روی والد ثابت صفحه ثبت میشود و برای هر عنصر فرزندی، چه از قبل وجود داشته باشد و چه بعداً اضافه شود، بهدرستی کار میکند.
شناسایی عنصر واقعی هدف با event.target
وقتی شنونده روی عنصر والد ثبت میشود، ویژگی event.target دقیقاً همان عنصری را برمیگرداند که کاربر روی آن کلیک کرده، نه لزوماً عنصری که شنونده روی آن نصب شده. این تفاوت بین event.target و event.currentTarget اساس کار Delegation است:
| ویژگی | event.target | event.currentTarget |
|---|---|---|
| مقدار | عنصری که رویداد از آن شروع شده | عنصری که شنونده روی آن ثبت شده |
| تغییر در طول انتشار رویداد | ثابت میماند | در هر مرحله به عنصر جاری تغییر میکند |
| کاربرد در Delegation | شناسایی عنصر واقعی کلیکشده | معمولاً کاربرد مستقیمی در Delegation ندارد |
پیادهسازی عملی یک لیست پویا
در مثال زیر، بهجای ثبت شنونده روی هر li، یک شنونده روی عنصر ul ثبت شده و با استفاده از متد closest، نزدیکترین li نسبت به عنصر کلیکشده پیدا میشود:
استفاده از closest("li") بهجای بررسی مستقیم event.target اهمیت زیادی دارد، چون اگر داخل هر li عنصر دیگری مثل یک آیکن یا span وجود داشته باشد، کلیک روی آن عنصر داخلی رخ میدهد و event.target به آن اشاره میکند، نه به خود li. متد closest با بالا رفتن از درخت DOM، نزدیکترین اجداد منطبق با سلکتور را پیدا میکند و این مشکل را برطرف میسازد.
محدودیتهای Event Delegation
این الگو برای همهی رویدادها مناسب نیست. رویدادهایی مثل focus و blur بهصورت پیشفرض Bubble نمیشوند و باید یا از نسخهی جایگزین آنها یعنی focusin و focusout استفاده کرد، یا شنونده را مستقیماً روی عنصر مورد نظر ثبت کرد. همچنین در درختان DOM بسیار عمیق، هر بار اجرای closest کمی هزینهی پردازشی دارد که در حجم بالای رویداد قابل بررسی است.
نکات کلیدی
- Event Delegation از رفتار Bubbling استفاده میکند تا با یک شنونده، رویدادهای چندین عنصر فرزند مدیریت شود.
event.targetعنصر واقعی کلیکشده را نشان میدهد وevent.currentTargetعنصر دارای شنونده را.- متد
closest()برای پیدا کردن عنصر والد منطبق با یک سلکتور، حتی وقتی کلیک روی فرزندان داخلی رخ داده، ضروری است. - این الگو برای عناصر پویا که بعداً به صفحه اضافه میشوند نیز بدون نیاز به ثبت شنوندهی جدید کار میکند.
- رویدادهایی مثل
focusوblurBubble نمیشوند و برای Delegation باید ازfocusin/focusoutاستفاده کرد.
جمعبندی
Event Delegation یکی از کاربردیترین الگوهای مبتنی بر Bubbling در جاوااسکریپت است که با ثبت یک شنونده روی عنصر والد، مدیریت رویداد برای تعداد نامحدودی عنصر فرزند، از جمله عناصری که بعداً بهصورت پویا اضافه میشوند، ممکن میشود. ترکیب event.target با متد closest() ابزار اصلی برای شناسایی دقیق عنصر هدف در این الگو است. با این حال، باید به رویدادهایی که Bubble نمیشوند توجه داشت و از جایگزین مناسب آنها استفاده کرد.
