Bubbling در مقابل Capturing

تا اینجا دیدیم که bubbling زمانی اتفاق میافته که یک رویداد از اون نود که اون رو dispatch کرده به سمت بالای tree حرکت میکنه، اما جاوا اسکریپت همچنین یک راه جایگزین bubbling به اسم capturing فراهم کرده.

Event capturing زمانی اتفاق میافته که رویداد ها به ترتیب برعکس bubbling هندل میشن، یعنی اعلان هایی که نود مربوط به رویداد فرستاده از بالا به پایین گرفته (capture) میشن. این یعنی اینکه وقتی با یک نود تعاملی برقرار میشه، هندلر های رویداد اون node ممکنه اولین کسایی نباشن که اون رویداد رو بگیرن. به جاش، یک parent (یا ancestor) ممکنه اول از همه اون رویداد رو دریافت کنه. اگه یکی از اون هندلر های مربوط به اون ancestor ها رویداد رو قطع کنن، هندلر های اون نود که باعث به وجود اومدن اون رویداد شده ممکنه اصلا فراخوانی نشن:

event_capturing_vs_bubbling_tree

برای اینکه یک هندلر رویداد رو به یک capture event متصل کنید، باید یک پارامتر سوم به همون متد addEventListener بدید. این پارامتر به عنوان useCapture شناخته میشه و مقدارش Boolean هست. اگه مقدارش به true ست بشه، رویداد داده شده در حالت capture بهش واگذاری میشه. اگه پارامتر useCapture رو به addEventListener ندادید، مقدار اون به صورت پیش فرض به false تنظیم میشه:

var clickHandler = () => console.log("clicked");
document.body.addEventListener("click", clickHandler);
// ==> clicked

هندلر هایی که به capture event ها متصل میشن، توی جای متفاوتی نسبت به bubbling event listener ها قرار میگیرن. زمانی که capture event ها رو اختصاص میدیم، اونها مزاحم bubbling event نمیشن. بنابراین، زمانی که یک رفرنس از یک فانکشن رو به عنوان هندلر های هردوی bubbling event و capture event ها توی یک نود و برای یک نوع رویداد تنظیم میکنیم، به این معنیه که زمانی که اون رویداد فرستاده بشه، فانکشن مورد نظر دوبار کال میشه:

var clickHandler = () => console.log("clicked");
document.body.addEventListener("click", clickHandler);
document.body.addEventListener("click", clickHandler, true);
// ==> clicked
// ==> clicked

برای حذف یک رویداد که با true تنظیم کردن مقدار پارامتر useCapture اضافه شده، فقط کافیه همون مقدار رو به متد removeEventListener بدیم:

document.body.removeEventListener("click", clickHandler, true);