btn.Click+=new EventHandler(btn_Click); btn.Click+=new EventHandler(btn_Click2); btn.Click-=new EventHandler(btn_Click); page.Load+=new EventHandler(page_Load);
מכירים את הסינטקס? כך מצרפים/מורידים אירוע למאזין ב-#C. ניתן ליישם סינטקס זה גם ב-JavaScript בצד לקוח.
בעת כתיבת הסקריפט נתקלתי בכמה קשיים. += היא פעולה המחברת בין מספרים ומשרשרת מחרוזות. שלא כמו ב-#C, אי אפשר לגרום לה לעשות משהו אחר. מכאן נובע, שחייבים להשתמש במספרים או מחרוזות כדי לסכם את כל ה-EventHanlerים המשוייכים לאלמנט. החלטתי על מספרים.
מכיוון שמחלקות מחזירות את עצמן בביטוי ה-new, יש למצוא שיטה להחזיר מספר. השיטה היא שכתוב מתודת valueOf. מתודת ה-valueOf הינה מתודה פנימית שמופעלת בכל פעם שקוראים לערך של אובייקט, כמו למשל בפעולת חיבור, חיסור וכו' (כמו מתודת toString שנקראת אוטומטית בשרשור מחרוזות). הערך שהמתודה תחזיר הוא הערך שיוחזר מביטוי ה-new אל תוך פעולת החיבור או החיסור.
הערך עצמו צריך להיות מזהה ייחודי. השתמשתי בשיטה "בינארית" הבנויה מקומבינציות של חזקות של 2.
קצת על השיטה הבינארית
השיטה מאפשרת למספר פריטים בחזקות של 2 – 1, 2, 4, 8, 16 וכו'. כל חיבור של מספרים אלו ייתן קומבינציה אחת בלבד.
דוגמה:
13 = 8+4+1
26 = 16+8+2
כל חזקה של 2 מייצגת "ביט" במיקום ספציפי.
הביט הראשון הוא 0 והמספר המייצג אותו הוא 1 (2 בחזקת 0)
הביט השני הוא 1 והמספר המייצג אותו הוא 2 (2 בחזקת 1)
הביט השלישי הוא 2 והמספר המייצג אותו הוא 4 (2 בחזקת 2)
וכן הלאה…
כאשר ביט אינו פעיל, הוא אינו נמצא בקומבינציה. כמו ש-2 לא נמצא בקומבינציה של 13.
כדי לבדוק האם ביט "דלוק" בתוך מספר אחר, משתמשים באופרטור & המחזיר את אותו מספר אם הוא דלוק ו-0 אם לא.
בכל פעולת חיבור, הרפרנס לפונקציה מצטרף למערך של כל ה-handlers ומודבק אליו אותו אינדקס בחזקת 2. האינדקס נקבע עפ"י מספר ה-handlers.
לאלמנט שאליו רוצים להוסיף/להוריד events מצמידים מאפיין, נניח Click, המאותחל ל-0. כל += של EventHandler יוסיף לתוך המאפיין Click מספר כלשהו שהוא חזקה של 2. חיבור של כמה EventHandlerים לתוך Click ייתן מספר שפירוק שלו ירכיב קומבינציה אחת בלבד של חזקות של 2.
בנוסף למאפיין, נשייך לאלמנט event בעזרת attachEvent/addEventListener שבהפעלתו נרוץ על כל מערך ה-handlers, ובמידה והמאפיין המספרי מכיל את המזהה של ה-handler מהמערך, נפעיל את הפונקציה.
הסינטקס הסופי הוא כזה:
Event.Register(element1,"Click"); element1.Click+=new EventHandler(handler1); // valueOf returns 1. add 1 element1.Click+=new EventHandler(handler2); // valueOf returns 2. add 2 element1.Click-=new EventHandler(handler2); // valueOf returns 2. subtract 2 element1.Click+=new EventHandler(handler3); // valueOf returns 4. add 4
לאחר כל שורות הקוד, ערכו של המאפיין Click הינו 5. 5, לאחר פירוק בינארי, הופך ל-4+1, שמייצגים "ביטים" 0 ו-2. לכן, הפונקציות באינדקס 0 ו-2 יקראו.
לחיצה על האלמנט תרוץ על מערך ה-handlers ותפעיל את פונקציות 0 ו-2 כי הביטים שלהן דלוקים במאפיין Click.
הקוד במלואו:
<script type="text/javascript">
//<![CDATA[
function EventHandler(handler) {
this.Handler=handler;
this._index=EventHandler._allHandlers.length;
EventHandler._allHandlers.push(this);
}
EventHandler.prototype.valueOf=function () {
// if function is already in the list, return its value
for (var i=0;i<EventHandler._allHandlers.length;i++) {
handler=EventHandler._allHandlers[i];
if (handler.Handler==this.Handler && handler.registered) return Math.pow(2,i);
}
this.registered=true;
return Math.pow(2,this._index);
};
EventHandler._allHandlers=[];
if (typeof(Event)=="undefined") Event={};
Event.Register=function (element,name) {
element[name]=0;
var fire=function (e) { Event.Fire(element[name],e); };
if (element.attachEvent) element.attachEvent("on"+name.toLowerCase(),fire);
else element.addEventListener(name.toLowerCase(),fire,false);
};
Event.Fire=function (handlers,e) {
var idx=0;
// cache power function for better performance
var pow=Math.pow;
for (var i=0;i<EventHandler._allHandlers.length;i++) {
var idx=pow(2,i);
// if the current index in the power of 2 contained in the handles list, call the function
if ((handlers & idx)>0) EventHandler._allHandlers[i].Handler(e);
}
}
function handler1() { alert(1); }
function handler2() { alert(2); }
function handler3() { alert(3); }
function handler4() { alert(4); }
onload=function () {
var element1=document.getElementById("element1");
Event.Register(element1,"Click");
element1.Click+=new EventHandler(handler1);
element1.Click+=new EventHandler(handler2);
element1.Click-=new EventHandler(handler2);
element1.Click+=new EventHandler(handler3);
var element2=document.getElementById("element2");
Event.Register(element2,"Click");
element2.Click+=new EventHandler(handler1);
element2.Click+=new EventHandler(handler2);
};
//]]>
</script>
<div id="element1">element1</div>
<div id="element2">element2</div>
4 תגובות
כתיבת תגובה
אהבתי!!!
אני צריך עוד לעבור יותר על הקוד כדי להבין אותו טוב יותר, אבל ממש אהבתי את השיטה.
אגב, אם כבר אתה מבצע כאן תאימות דפדפנים, אפשר לשלוח לevent listener את אובייקט האירוע המתאים:
var fire=function (e) { Event.Fire(element[name],(e||window.event)); };attachEvent עובד עם event object משלו, ולא עם הגלובאלי (window.event) ממש כמו addEventListener.
הפעמים שכן צריך להתייחס אל window.event הן בשימוש בהשמה של events ללא event listener:
el.onclick=function (e) { e=e || window.event; // ... };וואלה, חידשת לי. תודה.
אגב, ה"זכור פרטים" לא עובד.
כתיבת תגובה
תגיות מותרות לשימוש בתוכן
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre>