DOM - מודל המסמך

ה-DOM הוא ייצוג של דף ה-HTML כמבנה עץ שאפשר לגשת אליו ולשנות אותו עם JavaScript.


מה זה DOM?

כשדפדפן טוען דף HTML, הוא יוצר מודל אובייקטים:

document
└── html
    ├── head
    │   └── title
    └── body
        ├── h1
        ├── div
        │   └── p
        └── button

JavaScript יכולה לגשת לכל אלמנט ולשנות אותו!


בחירת אלמנטים

לפי ID (יחיד)

const element = document.getElementById("myId");
console.log(element);
<div id="myId">תוכן</div>

לפי Class (רשימה)

const elements = document.getElementsByClassName("myClass");
console.log(elements);  // HTMLCollection

// גישה לאיבר ספציפי
console.log(elements[0]);

לפי תגית (רשימה)

const paragraphs = document.getElementsByTagName("p");

לפי Selector (מודרני - מומלץ!)

// בחירת אלמנט אחד (הראשון)
const element = document.querySelector(".myClass");
const header = document.querySelector("#header");
const firstP = document.querySelector("div p");

// בחירת כל האלמנטים
const allButtons = document.querySelectorAll("button");
const allItems = document.querySelectorAll(".item");

// מעבר על התוצאות
allButtons.forEach(btn => {
    console.log(btn.textContent);
});

שינוי תוכן

textContent - טקסט בלבד

const element = document.querySelector("#title");

// קריאה
console.log(element.textContent);

// שינוי
element.textContent = "כותרת חדשה";

innerHTML - עם HTML

const container = document.querySelector("#container");

// הוספת HTML
container.innerHTML = "<strong>טקסט מודגש</strong>";

// תוספת לקיים
container.innerHTML += "<p>פסקה חדשה</p>";

⚠️ זהירות: innerHTML יכול להיות מסוכן אם מכניסים קלט משתמש (XSS)!

innerText

// דומה ל-textContent אבל מתחשב ב-CSS
element.innerText = "טקסט שייראה";

שינוי סגנון (Style)

const box = document.querySelector("#box");

// שינוי style יחיד
box.style.backgroundColor = "blue";
box.style.fontSize = "20px";
box.style.padding = "10px";
box.style.borderRadius = "5px";

// שים לב: camelCase במקום kebab-case
// CSS: background-color → JS: backgroundColor
// CSS: font-size → JS: fontSize

שינוי Classes

const element = document.querySelector("#element");

// הוספת class
element.classList.add("active");

// הסרת class
element.classList.remove("active");

// החלפה (toggle)
element.classList.toggle("active");

// בדיקה
if (element.classList.contains("active")) {
    console.log("האלמנט פעיל");
}

// החלפת class אחד באחר
element.classList.replace("old", "new");

שינוי Attributes

const link = document.querySelector("a");

// קריאת attribute
console.log(link.getAttribute("href"));

// שינוי/הוספת attribute
link.setAttribute("href", "https://google.com");
link.setAttribute("target", "_blank");

// הסרת attribute
link.removeAttribute("target");

// בדיקה
if (link.hasAttribute("href")) {
    console.log("יש href");
}

תכונות נפוצות

const img = document.querySelector("img");
img.src = "image.jpg";
img.alt = "תיאור התמונה";

const input = document.querySelector("input");
input.value = "ערך חדש";
input.placeholder = "הכנס טקסט";
input.disabled = true;

const checkbox = document.querySelector('input[type="checkbox"]');
checkbox.checked = true;

יצירת אלמנטים חדשים

// יצירת אלמנט
const newDiv = document.createElement("div");
newDiv.textContent = "אני div חדש!";
newDiv.className = "box";
newDiv.id = "newBox";

// הוספה לדף
document.body.appendChild(newDiv);

// הוספה לאלמנט ספציפי
const container = document.querySelector("#container");
container.appendChild(newDiv);

הוספה במיקום ספציפי

const parent = document.querySelector("#parent");
const newElement = document.createElement("li");
newElement.textContent = "פריט חדש";

// בסוף
parent.appendChild(newElement);

// בהתחלה
parent.prepend(newElement);

// לפני אלמנט ספציפי
const reference = parent.querySelector(".specific");
parent.insertBefore(newElement, reference);

// אחרי אלמנט ספציפי
reference.after(newElement);

// לפני אלמנט ספציפי
reference.before(newElement);

הסרת אלמנטים

const element = document.querySelector("#toRemove");

// שיטה 1: remove() (מודרני)
element.remove();

// שיטה 2: דרך ההורה
const parent = document.querySelector("#parent");
parent.removeChild(element);

שכפול אלמנט

const original = document.querySelector("#original");

// שכפול ללא ילדים
const shallowClone = original.cloneNode(false);

// שכפול עם כל הילדים
const deepClone = original.cloneNode(true);

document.body.appendChild(deepClone);

ניווט בעץ ה-DOM

const element = document.querySelector("#element");

// הורה
element.parentElement;
element.parentNode;

// ילדים
element.children;          // HTMLCollection של אלמנטים
element.childNodes;        // NodeList כולל טקסט
element.firstElementChild;
element.lastElementChild;

// אחים
element.nextElementSibling;
element.previousElementSibling;

דוגמה מלאה

HTML

<!DOCTYPE html>
<html>
<head>
    <title>דוגמת DOM</title>
    <style>
        .highlight { background-color: yellow; }
        .hidden { display: none; }
    </style>
</head>
<body>
    <h1 id="title">כותרת</h1>
    <ul id="list">
        <li>פריט 1</li>
        <li>פריט 2</li>
    </ul>
    <button id="addBtn">הוסף פריט</button>
    <button id="toggleBtn">הסתר/הצג רשימה</button>

    <script src="app.js"></script>
</body>
</html>

JavaScript

// בחירת אלמנטים
const title = document.querySelector("#title");
const list = document.querySelector("#list");
const addBtn = document.querySelector("#addBtn");
const toggleBtn = document.querySelector("#toggleBtn");

// שינוי כותרת
title.textContent = "רשימת הפריטים שלי";
title.style.color = "blue";

// הוספת פריט חדש
addBtn.addEventListener("click", () => {
    const newItem = document.createElement("li");
    const itemCount = list.children.length + 1;
    newItem.textContent = `פריט ${itemCount}`;
    list.appendChild(newItem);
});

// הסתרה/הצגה של הרשימה
toggleBtn.addEventListener("click", () => {
    list.classList.toggle("hidden");
});

// הדגשה בלחיצה על פריט
list.addEventListener("click", (e) => {
    if (e.target.tagName === "LI") {
        e.target.classList.toggle("highlight");
    }
});

טיפים חשובים

1. ממתינים שהדף ייטען

<!-- אפשרות 1: script בסוף -->
<body>
    <!-- תוכן -->
    <script src="app.js"></script>
</body>

<!-- אפשרות 2: defer -->
<head>
    <script src="app.js" defer></script>
</head>

<!-- אפשרות 3: DOMContentLoaded -->
<script>
document.addEventListener("DOMContentLoaded", () => {
    // הקוד שלך כאן
});
</script>

2. ביצועים

// ❌ לא יעיל - גורם לreflow בכל איטרציה
for (let i = 0; i < 100; i++) {
    document.body.innerHTML += `<div>${i}</div>`;
}

// ✅ יעיל - שינוי אחד
let html = "";
for (let i = 0; i < 100; i++) {
    html += `<div>${i}</div>`;
}
document.body.innerHTML = html;

// ✅ יעיל יותר - DocumentFragment
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
    const div = document.createElement("div");
    div.textContent = i;
    fragment.appendChild(div);
}
document.body.appendChild(fragment);

סיכום

פעולה מתודה
בחירה לפי ID getElementById("id")
בחירה לפי selector querySelector("selector")
בחירת כולם querySelectorAll("selector")
שינוי טקסט element.textContent = "..."
שינוי HTML element.innerHTML = "..."
שינוי סגנון element.style.property = "..."
הוספת class element.classList.add("...")
יצירת אלמנט document.createElement("tag")
הוספה לדף parent.appendChild(element)
הסרה element.remove()

בדקו את עצמכם

נסו לענות לבד לפני שאתם פותחים את התשובה.

  1. מה ההבדל בין textContent ל-innerHTML?

    1. אין הבדל
    2. textContent לא קיים
    3. textContent מכניס טקסט בלבד, innerHTML מפרש HTML, ולכן מסוכן עם קלט משתמש
    4. innerHTML מהיר יותר תמיד
    הצגת התשובה

    תשובה ג. innerHTML עם קלט של משתמש פותח פרצת XSS.

  2. מה מחזיר document.querySelector('.card')?

    1. את כל האלמנטים עם הקלאס
    2. את האלמנט הראשון שמתאים, או null
    3. תמיד שגיאה
    4. מערך
    הצגת התשובה

    תשובה ב. לכל האלמנטים משתמשים ב-querySelectorAll.