Dev-Time

Events

הקדמה

לא פעם שמעתי את האמירה “נו מה יש לכפתור הזה?? למה הוא לא עובד?!”
כשאני נגש לאותו מפתח שאומר את זה, אני שואל אותו – בדקת אולי זה תהליך ה-bubbling שיש לאירועים בדפדפן?
מכאן אני מגיע לצומת שיש בו ( צומת זה זכר ) 2 תשובות אפשרויות:
1. כן בדקתי זאת לא הבעיה.
2. event bubbling? שמעתי על זה משהו.. אבל מה זה?
גם אם התשובה שלכם היא 1 וגם אם היא 2.
לא משנה איפה אתם פונים בצומת הזה, אני מציע לכם קצת לרענן את הנושא האירועים – events.


שנתחיל?

לפני שנצלול לbubbling וcapturing שזה רק חלק מנושא האירועים בדפדפן.
אני רוצה דווקא לעבור איתכם על אירועים וכיצד הם מתרחשים.
באופן כללי וגס – אירועים הם אינטרקציות אשר מתרחשות בדפדפן והן מתחלקות לשנים:
1. אינטרקציה (אירוע) מצד הדפדפן כמו טעינה של עמוד או תמונה וכו..
2. אינטרקציה (אירוע) מצד המשתמש כמו גלילה בגלגלת העכבר או לחיצה על כפתור המקלדת וכו..
3. אירועי custom שנוצרים ונורים תוכנתית.

ישנן כמה דרכים להאזין לאירועים בדפדפן, במאמר זה אציג לכם כיצד ניתן להאזין לאירועים בדפדפן.

inline event handler

inline event handler כשמו כן הוא – אנו כותבים את האירוע בתוך התגית של האלמנט או מוסיפים את המתודה הרצויה של האירוע הרצוי.
רבים מכירים את השיטה בעקבות השימוש של אנגולר בה. זה מאוד מזכיר את כדוגמא את ה(click) שאנו כותבים באנגולר בשביל ליצור אירוע הקלקה.
כאן תוכלו לראות 2 דוגמאות שהכנתי כיצד מצמידים אירועים לאלמנט בצורת inline:

See the Pen event-exaple-inline-object by Matan (@matanyo) on CodePen.

See the Pen event-example-object by Matan (@matanyo) on CodePen.

אני מציע לכם לפתוח את הקודפן עצמו של הדגמאות ולראות שלאחר לחיצה על הכפתור הconsole יציג לכם רפרנס לאובייקט של הכפתור.
בתוך האובייקט הגדול הזה, יש בין היתר רשימה ארוכה של אירועים שתמיד יתחילו עם on, כגון onclick , onmouseover ועוד רבים וטובים.

לעצלנים שלא רצו לפתוח את הקודפן ולראות כיצד האובייקט נראה. הנה צילום מסך של האובייקט.
כפי שאתם רואים שאר המתודות של האירועים עם הערך null למעט onclick שהוספתי לצורך הדוגמה.
חשוב: אחד החסרונות של השיטה הוא שכל פונקציה שנרצה להריץ חייבת להיות חשופה בסקופ הגלובלי.


Event Listener
W3C בשנת 2000 שחררה את DOM level 2 events שבין הדברים הביאה איתה את EventTarget שהציעה דרך חכמה יותר לשלוט באירועים.
EventTarget הוא אובייקט מיוחד שנוצר בדפדפן ועליו שלוש מתודות :

  1. addEventListener
  2. removeEventListener
  3. dispatchEvent

addEventListener

See the Pen eventlistener-example by Matan (@matanyo) on CodePen.

בואו נבין מה יש לנו כאן,   addEventListener מקבלת שלושה פרמטרים:
1. מחרוזת של סוג האירוע ללא הprefix של on : חובה
2. פונקציה (callback) שאותה נריץ בהפעלת האירוע : חובה
3.  useCapture של אירוע, שהוא למעשה ערך בוליאני ששולט על התנהגות האירוע בין capturing לבין bubbling כשהדיפולט שלו הוא falseלא חובה
הפרמטר השלישי הוא המעניין שבהם ואליו ארחיב יותר לעומק בהמשך.
בשונה מinline event handler שראינו כיצד אנחנו מוסיפים מתודה של onclick כדגומה, כאן הסיפור הוא קצת שונה, אנחנו לא מרחיבים את האובייקט של האלמנט עצמו אלא מפעילים מתודה שיושבת על EventTarget שמגיעה עם כל אובייקט שתומך באירועים-  אלמנטים,  document ,ואפילו XMLHttpRequest ועוד..
דבר נוסף שaddEventListener מאפשר לעשות, הוא להוסיף כמה אירועים שנרצה על אלמנט בשונה בonclick אשר יכול מאפשר פעם אחת בלבד.
כיוון שאין לנו גישה לקוד של מנוע הJavascript בדפדפן וכיצד הוא מקמפל את הקוד שלנו מאוחרי הקלעים.
הקוד מוצג לנו כ-native code וכך זה יראה :

removeEventListener

בטח כבר ניחשתם שאם אפשר להוסיף אירוע אז גם ניתן להסיר אותו. וזה נעשה על ידי removeEventListener שיכול להסיר כל אירוע שיצרתם.

See the Pen removeeventlistener-example by Matan (@matanyo) on CodePen.

דגשים חשובים לגבי שימוש בremoveEventListener:
1. הפונקציה שעוברת דרך הפרמטר השני חייבת להיות רפרנס לפונקציה חיצונית (ולא callback כמו שהראתי בשאר הדוגמאות) כיוון callback אינו ניתן להצבעה ולכן לא יהיה ניתן להסירו.
2. הפרמטר השלישי useCapture חייב להיות זהה לפרמטר השלישי ב addEventListener בשביל להסירו.

dispatchEvent
בשונה מ2 המתודות הקודמות שראינו אשר יוצרות אירועים, dispatchEvent מריצה אותם.
השימוש העיקרי למתודה הזאת הוא לצורך הרצה של אירועים מיוחדים שאנו מייצרים כnew event או new custom event.
וזה נראה כך:

dispatchEvent מקבלת שני פרמטרים:
1. target – האלמנט בDOM שהdispatchEvent צריכה לתפוס בשביל להאזין לאירוע שיש עליו: חובה
2. event – האירוע  שאותו נשלח בעת ההרצה (new event או new custom event): חובה
הדרך להפסיק את ההרצה של האירוע היא על ידי המתודה ()event.preventDefault .
ארחיב לעומק במאמר נפרד כיצד ליצור custom event וכיצד להיעזר בdispatchEvent.


הגענו ללב ליבו של המאמר, והסיבה העיקרית שהוא נכתב.
כשנורה אירוע על אלמנט בDOM, נוצר מאוחרי הקלעים תהליך שנקרא propagation ואלו הם 4 השלבים שלו:

1. Event.NONE – עדיין לא מתרחש דבר.
2. Event.CAPTURING_PHASE – השלב ההתחלתי שבו האירוע מתחיל דרכו מהאלמנט העליון בDOM ועד ליעד (האלמנט שממנו נורה האירוע).
3. Event.AT_TARGET – היעד שלנו (האלמנט שממנו נורה האירוע).
4. Event.BUBBLING_PHASE – הדרך חזרה שמתחילה ביעד שקבענו עד לאלמנט הראשון בDOM.

Capturing

למעשה השלב הראשון בתהליך ה- propagation של כל אירוע בDOM הוא Capturing.
כשנורה אירוע מאלמנט מסוים, הדפדפן  מאוחרי הקלעים מתחיל תהליך שנקרא propagation בעץ של ה-DOM (לרוב יתחיל באלמנט הhtml) והוא עושה drill down עד שהוא מגיע לאלמנט שממנו נורה האירוע.
כל התהליך הזה נקרא Capturing.
הדרך לשלוט בתהליך הזה, היא על ידי המתודה addEventListener כשפרמטר האחרון שלה הוא useCapture , במידה ונגדיר את הפרמטר כtrue, הדפדפן ירה את כל האירועים הנמצאים במורד העץ ההיררכי ב-DOM עד שיגיע לאלמנט שנורה ממנו את האירוע שלנו.

דוגמה להמחשה – לחצו על אחד מהאלמנט ותראו כיצד Capturing פועל עד שהוא מגיע לאלמנט שעליו לחצתם.

See the Pen Capturing – example by Matan (@matanyo) on CodePen.

Target

רפרנס לאלמנט/האובייקט שירה את האירוע. עושים בזה שימוש רב כשרוצים לעשות מניפולציות על האלמנט שעליו התרחש אירוע.
חשוב לשים לב שזה לא currentTarget אלא target כלומר, האלמנט שאליו הוספנו את הaddEventListener.

דוגמה לכך :

See the Pen target – example by Matan (@matanyo) on CodePen.

אם תלחצו על כל אלמנט תקבלו רפרנס אל האלמנט עצמו, בעוד שהאירוע עצמו הוצמד ל<body>.
במידה והיינו מבקשים להציג לנו את currentTarget היינו מקבלים תמיד את ה<body> ולא את האלמנט שבאמת ירה את האירוע.
חשוב – הthis בכל אירוע שאנו מייצרים תמיד יהיה רפרנס לcurrentTarget ולא לtarget עצמו.
אם מעניין אותכם להתעמק ולהבין כיצד עובד הthis, אתם מוזמנים לקרוא את המאמר הבא.

Bubbling

השלב האחרון לאחר שהאירוע התחרש הוא bubbling –  עלייה לאורך ההירככית האבות בDOM.
בדומה לCapturing הפרמטר השלישי (האחרון) בaddEventListener הוא זה שקובע האם האירוע יהיה במצב של Bubbling או Capturing. כברירת מחדל הוא נמצא על false שזה מצב של Bubbling.
הנה דוגמה מאוד דומה לדוגמה של Capturing רק שהפרמטר (useCapture) הוא false.

See the Pen Bubbling – example by Matan (@matanyo) on CodePen.

יש כמה אירועים שאינם פועלים עם bubbling כגון focus.


stopPropagation

עד כה הצגתי כיצד ניתן לשלוט בbubbling וcapturing המתרחשים באירועים בDOM.
אבל כיצד ניתן לעצור או למנוע מהתהליכים האלו לקרות?
אז יש דרך – והיא נקראת ()stopPropagation – זוהי אחת מן המתודות אשר יושבות בevent.
שכל מטרתה היא לעצור את הpapgragtion שיש באירועים בDOM.
אקח את הדוגמה של הBubbling ופשוט אמנע ממנה לבצע את תהליך הbubble על ידי ()event.stopPropagation .

See the Pen stopPopgragtion- example by Matan (@matanyo) on CodePen.

אם תלחצו על <h1> תראו שהוא מציג הודעה רק על האלמנט <h1> ולא ממשיך כפי שבדוגמה של הbubbling.

preventDefault

מתודה נוספות שנמצאת בevent המגיע לנו בכל אירוע.
preventDefault בעצם יבטל את כל הפעולות/אירועים שהuser agent של הדפדפן מריץ על אלמנטים.
בין הדוגמאות הקלאסית ביותר הם על אלמנט ה<a> עם href שיודע לנווט אותנו בתוך הדפדפן.

See the Pen preventDefault – example by Matan (@matanyo) on CodePen.

שימו לב שהלינק הראשון באמת יעביר אותכם לכתובת שהזנתי בhref , בעוד שהלינק השני לא מעביר לשום מקום אלא בעת לחיצה ימנע מהדפדפן לעשות את התהנגות הדיפולטיבית ויפעיל את האנימציה שיצרתי.

 


מקורות קריאה:

w3

javascript.info

MDN

 

מתן יוסף

תמיד מתעניין ורוצה לדעת עוד..
יש לכם משהו לשאול או להעיר?
קישור ללינקדאין שלי ↓

2 comments

  • המאמר הזה לא מעודכן.
    הוא רלוונטי ל-ES5, החל מ-ES2015 במקום useCapture מעבירים אובייקט options. גם שום מילה לא נאמרה על once ו-passive. בקיצור – פשטני מדי.

Follow

Get every new post delivered to your Inbox

Join other followers