
מבוא ל-DOM
מודל אובייקט המסמך (Document Object Model) ובקיצור DOM הוא ממשק תכנות למסמכי אינטרנט (עמודי HTML). הממשק מייצג את המסמך כצמתים ואובייקטים, כך שבאמצעות תיכנות ניתן לשנות את מבנה המסמך, הסגנון והתוכן שלו.
למעשה, ה-DOM הוא מבנה דמוי עץ שבו כל צומת הוא אובייקט המייצג חלק מהמסמך. אובייקט המסמך הוא השורש, וכל אלמנט, תכונה וכל פיסת טקסט במסמך הם צומת.
הבנת ה-DOM חיונית לפיתוח אתרים, מכיוון שהיא מאפשרת לך:
- לשנות באופן דינמי תוכן של דף אינטרנט.
- לשנות באופן דינמי מבנה (פריסה ועיצוב) של דף אינטרנט.
- לטפל באירועים כמו קליקים, הגשת טפסים וכו'.
- ליצור יישומי אינטרנט אינטראקטיביים ודינמיים.
גישה לרכיבי DOM באמצעות ג'אווה סקריפט
כדי לנהל את ה-DOM, ניגשים תחילה לאלמנטים אותם רוצים לשנות, באמצעות מתודות שונות של האובייקט document. נסקור את המתודות האלו להלן.
getElementById - מתודה זו מחזירה אלמנט יחיד לפי המזהה שלו. כלומר, היא מחפשת ב-HTML את האלמנט שמוגדר לו המזהה (id) הנתון ומחזירה אותו.
דוגמה:
let element = document.getElementById('myElement');
getElementsByClassName - מתודה זו מחזירה את כל האלמנטים עם מחלקה (class) נתונה.
דוגמה:
let elements = document.getElementsByClassName('myClass');
getElementsByTagName - מתודה זו מחזירה את כל האלמנטים עם תג נתון. תג יכול להיות לדוגמה div, p, a, img וכן הלאה.
דוגמה:
let elements = document.getElementsByTagName('div');
querySelector - מתודה זו מחזירה את האלמנט הראשון שמתאים לסלקטור CSS נתון.
דוגמה:
let element = document.querySelector('.myClass');
querySelectorAll - מתודה זו מחזירה את כל האלמנטים שמתאימים לסלקטור CSS נתון.
דוגמה:
let elements = document.querySelectorAll('.myClass');
במקרים בהם נעשה שימוש רב וחוזר באלמנט מסויים, ניתן לעשות שימוש ברעיון הסגירות (closure), כדי ליעל את העבודה ולחסוך זמני ביצוע.
דוגמה:
const getElement = (function() {
let element;
return function() {
if (!element) {
element = document.getElementById('myElement');
}
return element;
}
})();
בדוגמה זו, הגדרנו את הפונקציה getElement (השמה של פונקציה אנונימית לקבוע getElement כמוה כהגדרת פונקציה), אשר כוללת בתוכה את המשתנה element. בכל פניה אל getElement, אם element אינו מוגדר, אז הוא יקבל את הערך של האלמנט עם המזהה myElement, ובסיום יוחזר element. באופן הזה, הפונקציה getElement למעשה מחזירה את האלמנט myElement, אך מחשבת אותו פעם אחת בלבד, בפניה הראשונה לפונקציה (כי רק אז המשתנה element אינו מוגדר).
לאחר הגישה לאלמנטים, ניתן לתפעל אותם: שינוי התוכן, התכונות, הסגנונות שלהם ועוד. נסקור להלן כמה אפשרויות נפוצות במיוחד למניפולציות ב-DOM.
שינוי תוכן אלמנטים ב-DOM
שינוי תוכן לאלמנט ניתן לבצע באמצעות עדכון אחד מהמאפיינים הבאים: innerHTML, textContent, innerText.
דוגמה:
element.innerHTML = '<p>New Content</p>';
element.textContent = 'New Content';
element.innerText = 'New Content';
שלושת המאפיינים לעיל משנים את התוכן של האלמנט, אך יש ביניהם מספר הבדלים. סידרנו את ההבדלים בטבלה הבאה.
מאפיין | מבצע פארסינג (ניתוח) ל-HTML | כולל טקסט נסתר | מתעדכן דינמית | שימושים נפוצים |
---|---|---|---|---|
innerHTML | כן | כן | לא | כשרוצים לשמור על מבנה תגיות ה-HTML |
textContent | לא | כן | לא | כשרוצים להכניס טקסט ללא תגיות באופן מהיר ומאובטח |
innerText | לא | לא | כן | כשרוצים לשמור על עיצוב ה-CSS ולוודא עדכון דינמי |
שימוש ב-innerHTML נועד במקרה שצריך להכניס תוכן HTML באופן דינמי, כגון עיבוד רשימה של פריטים.
דוגמה:
let items = ['<li>Item 1</li>', '<li>Item 2</li>'];
element.innerHTML = items.join('');
שימוש ב-textContent נועד במקרה של קלט מהמשתמש ומבטיח שתגי HTML בקלט יטופלו כטקסט רגיל. כך נמנע התקפות XSS (התקפות בהן המשתמש מכניס במכוון קטעי קוד במקום טקסט כקלט).
דוגמה:
let userInput = '<script>alert("XSS")</script>';
element.textContent = userInput; // Displays the text as-is, without executing the script.
שימוש ב-innerText נועד במקרה שרוצים להציג טקסט המכבד את מאפייני ה-CSS שהוחלו על האלמנט, כגון הסתרת טקסט על סמך CSS.
דוגמה:
element.style.display = 'none';
element.innerText = 'This text will be hidden.';
שינוי מאפייני אלמנטים ב-DOM
המתודה getAttribute מחזירה תכונה של אלמנט. המתודה setAttribute משנה תכונה של אלמנט. המתודה removeAttribute מסירה תכונה של אלמנט.
דוגמה:
element.setAttribute('src', 'image.jpg');
let src = element.getAttribute('src');
element.removeAttribute('src');
שינוי עיצוב אלמנטים ב-DOM
ניתן לשנות את הסגנון של אלמנט על ידי שינוי המאפיין style שלו או באמצעות שימוש ב-classList להוספה והסרה של מחלקות שהוגדר להן סגנון עיצוב מראש.
דוגמה:
element.style.color = 'red';
element.style.fontSize = '20px';
element.classList.add('newClass');
element.classList.remove('oldClass');
יצירה ומחיקה דינמית של אלמנטים ב-DOM
ניתן ליצור אלמנטים חדשים באמצעות המתודה createElement. ניתן להוסיף אלמנטים ל-DOM באמצעות המתודה appendChild. ניתן למחוק אלמנטים באמצעות המתודה remove.
באמצעות היכולות להוסיף ולהסיר אלמנטים בצורה דינמית, ניתן ליצור HTML דינמי שמתעדכן בזמן אמת.
דוגמה:
let newElement = document.createElement('div');
newElement.textContent = 'New Element';
document.body.appendChild(newElement);
element.remove();
בדוגמה זו, יצרנו אלמנט חדש מסוג div והכנסנו לו את הטקסט New Element. באמצעות המתודה appendChild, הוספנו את האלמנט אחרון ברשימת האלמנטים בתוך האלמנט body. לסיום, הסרנו אלמנט אחר בשם element.
ניווט בין אלמנטים ב-DOM
שפת JavaScript מספקת מספר מאפיינים שמאפשרים לנווט בין אלמנטים שונים במסמך ה-HTML.
בעת הניווט מתייחסים לכל אלמנט כצומת (node) בעץ האלמנטים. לכל אלמנט נתון ניתן להגדיר את הקשרים הבאים: צומת אב (האלמנט המחזיק את האלמנט הנתון), צומת בן (אלמנט פנימי שהאלמנט הנתון הוא האב שלו), צומת אח (אלמנט נוסף שחולק צומת אב משותף עם האלמנט הנתון).
להלן המאפיינים שמאפשרים את הניווט בצמתים:
parentNode - מחזיר את צומת האב של אלמנט.
childNodes - מחזיר אוסף של צמתים בנים של אלמנט.
firstChild - מחזיר את צומת הבן הראשון.
lastChild - מחזיר את צומת הבן האחרון.
previousSibling - מחזיר את צומת האח הקודם.
nextSibling - מחזיר את צומת האח הבא.
דוגמה:
let parent = element.parentNode;
let children = element.childNodes;
let firstChild = element.firstChild;
let lastChild = element.lastChild;
let previous = element.previousSibling;
let next = element.nextSibling;
בעת גישה לרכיבים מרובים, נקבל אובייקטים מסוג NodeList או HTMLCollection. אלו הם אובייקטים דמויי מערך, אך אינם באמת מערכים. ניתן להשתמש במתודה Array.from או באופרטור Spread (3 נקודות), כדי להמיר אותם למערכים.
דוגמה:
let nodeList = document.querySelectorAll('div');
let array = Array.from(nodeList);
let anotherArray = [...nodeList];
בדוגמה זו אנו מחפשים את כל האלמנטים עם הסלקטור div. הערך המוחזר הוא מסוג nodeList ונרצה להמיר אותו למערך. נעשה זאת ב-2 צורות: בפעם הראשונה באמצעות Array.from ובפעם השניה באמצעות 3 נקודות.
דוגמה נוספת:
// Access all paragraph elements using querySelectorAll
const paragraphs = document.querySelectorAll('p');
// Convert NodeList to an array and iterate over each paragraph to apply a class
paragraphs.forEach(paragraph => {
paragraph.classList.add('highlight');
});
בדוגמה זו אנו מחפשים את כל האלמנטים עם הסלקטור p (פיסקאות). בעזרת המתודה forEach אנו עוברים על כלל האלמנטים שקיבלנו, ולכל אחד ניגשים ל-classList שלו (רשימת המחלקות שלו) ומוסיפים את המחלקה highlight.