מימוש Bindings ב JavaScript ללא ספריות
פוסט זה כולל טיפ קצר בנושא פיתוח Front End. אם אתם רוצים ללמוד יותר לעומק על פיתוח Front End מהבסיס ועד הנושאים המתקדמים תשמחו לשמוע שבניתי קורס וידאו מקיף בנושא זה הכולל מעל 50 שיעורי וידאו והמון תרגול מעשי.
למידע נוסף והצטרפות לקורס בקרו בדף קורס Front End באתר.
בעבר מתכנתים רבים השתמשו במאפיינים מסוג onClick על הכפתורים כדי לחבר קוד לאירועים. לימים, המעבר לפיתוח מונחה עצמים די ביטל אפשרות זו, מאחר והפונקציות כבר לא היו זמינות באופן גלובלי (אלא רק כשדות של אוביקטים).
אבל קשירת אירועים מתוך HTML עדיין נראית כרעיון טוב במצבים מסוימים. זה נוח שהכל נמצא במקום אחד (לראיה הפופולריות של ריאקט). בפוסט זה נבנה מנגנון bindings פשוט בעצמנו ואני מקוה שזה יעזור לכם להבין איך מנגנונים כאלה בנויים.
1. מה נרצה להשיג
בהנתן ה HTML הבא, הייתי רוצה לייצר 3 מוני לחיצות נפרדים ו Monitor יחיד אחריהם, כל רכיב מבוסס על הטמפלייט שלו שמוגדר בתחתית העמוד בקטע script:
<div class="view" data-controller="clicker"></div>
<div class="view" data-controller="clicker"></div>
<div class="view" data-controller="clicker"></div>
<div class="view" data-controller="monitor"></div>
<script type="text/template" id="tmpl-clicker">
<div class="clicker">
<p>You clicked
<span class="res">0</span>
times
<button class="autobind" data-click="inc">Click Here</button>
</div>
</script>
<script type="text/template" id="tmpl-monitor">
<div class="monitor" >
<div class="autobind" data-mousemove="update" style="width:300px;height:300px;border:2px solid blue">
<span class="x"></span>
<span class="y"></span>
</div>
</div>
</script>
יותר מזה, ארצה שכל קוד ה JavaScript שיהיה על משתמש לכתוב כדי לבנות קוד למונה לחיצות יסתכם בקוד שנראה בערך כך:
class Clicker extends BaseController {
constructor(el) {
super(el);
this.val = 0;
}
inc() {
this.el.querySelector('.res').textContent = ++this.val;
}
}
כלומר התבנית מגדירה כיצד יראה הפקד, וגם מה יקרה כשילחצו על הכפתור, וה JavaScript מגדיר רק את מימוש הפונקציה inc.
2. אופן המימוש
המפתח ליישום הוא המחלקה BaseController ממנה הפקד יורש. מחלקה זו מקבלת הזדמנות בעת יצירת הפקד לקרוא את קוד התבנית ולהוסיף event handlers לפי מה שצוין ב HTML. כך נראה קוד המחלקה:
const EVENTS = ['click', 'mousemove'];
class BaseController {
constructor(el) {
const templateId = 'tmpl-' + this.constructor.name.toLowerCase();
const _html = document.getElementById(templateId).innerHTML;
el.innerHTML = _html;
this.el = el;
const tobind = el.querySelectorAll('.autobind');
for (let i=0; i<tobind.length; i++) {
for (let evName of EVENTS) {
const handlerName = tobind[i].dataset[evName];
if (!handlerName) continue;
tobind[i].addEventListener(evName, this[handlerName].bind(this));
}
}
}
}
עבודת ה binding מתבצעת בלולאה הכפולה בתחתית פונקציית הבנאי. לכל אלמנט ב HTML המכיל את הקלאס autobind, ולכל אחד מהאירועים שמוגדרים במערך EVENTS נפעיל את addEventListener עם שם האירוע ופונקציית הטיפול הרלוונטית.
3. אתחול הפקדים
הלולאה האחרונה שעלינו לכתוב היא קובץ ה main שמאתחל את כל הפקדים. מאחר ושם הפקד מצוין ב HTML נוכל להשתמש בלולאה כדי לייצר אותם באופן דינמי:
const CONTROLLERS = {
clicker: Clicker,
monitor: Monitor,
};
for (let i=0; i<views.length; i++) {
const v = views[i];
if (!v.dataset.controller) continue;
new CONTROLLERS[v.dataset.controller](v);
}
ואפשר לראות את הקוד כולו בפעולה כאן:
4. סיכום
אז מה המסקנה? האם נזרוק את אנגולר ונחזור לכתוב את כל קוד ה bindings מאפס באמצעות JavaScript? לא הייתי ממהר לשם. אנגולר עושה הרבה יותר מה bindings המצ'וקמק שהוצג כאן בפוסט. מה שכן כדאי לזכור ש JavaScript היא שפה מאוד גמישה. לפני שאתם רצים ללמוד את הספריה הגדולה הבאה שתשנה את העולם, כדאי להשקיע עוד רגע בללמוד את היסודות ולהבין איך להשתמש ב JavaScript עצמה כדי לפתור בעיות.