לדלג לתוכן

3.2 בחירת ושינוי אלמנטים הרצאה

בחירת אלמנטים - selecting elements

כדי לעשות משהו עם אלמנט ב-DOM, קודם צריך למצוא אותו. יש כמה דרכים לבחור אלמנטים, ונלמד את כולן.

getElementById

הדרך הכי פשוטה - מחפש אלמנט לפי ה-id שלו:

<h1 id="main-title">Hello World</h1>
<p id="description">This is a paragraph.</p>
const title = document.getElementById("main-title");
const desc = document.getElementById("description");

console.log(title); // <h1 id="main-title">Hello World</h1>
console.log(desc);  // <p id="description">...</p>

// if no element with that id exists, returns null
const nothing = document.getElementById("nonexistent");
console.log(nothing); // null
  • מחזיר אלמנט בודד (או null אם לא נמצא)
  • ה-id צריך להיות ייחודי בדף - אם יש כפילויות, רק הראשון יוחזר
  • לא צריך לשים # לפני השם (זה לא סלקטור CSS)

querySelector

מחפש את האלמנט הראשון שמתאים לסלקטור CSS:

<div class="container">
    <p class="intro">First paragraph</p>
    <p class="intro">Second paragraph</p>
    <p>Third paragraph</p>
</div>
// select by class
const intro = document.querySelector(".intro");
console.log(intro); // the FIRST .intro element

// select by tag
const firstP = document.querySelector("p");
console.log(firstP); // the first p in the document

// select by complex CSS selector
const containerP = document.querySelector(".container > p");

// select by attribute
const input = document.querySelector('input[type="email"]');

// select by id (works, but getElementById is faster)
const title = document.querySelector("#main-title");
  • מחזיר אלמנט בודד - הראשון שמתאים
  • אם אף אלמנט לא מתאים, מחזיר null
  • מקבל כל סלקטור CSS תקין
  • זו הדרך הכי נפוצה לבחור אלמנטים - נשתמש בה הרבה

querySelectorAll

מחפש את כל האלמנטים שמתאימים לסלקטור CSS:

<ul>
    <li class="item">Item 1</li>
    <li class="item active">Item 2</li>
    <li class="item">Item 3</li>
    <li class="item active">Item 4</li>
</ul>
// get all items
const allItems = document.querySelectorAll(".item");
console.log(allItems); // NodeList(4) [li, li, li, li]
console.log(allItems.length); // 4

// get only active items
const activeItems = document.querySelectorAll(".item.active");
console.log(activeItems.length); // 2

// iterate with forEach
allItems.forEach(function(item) {
    console.log(item.textContent);
});

// iterate with for...of
for (const item of allItems) {
    console.log(item.textContent);
}

// access by index
console.log(allItems[0].textContent); // "Item 1"
console.log(allItems[2].textContent); // "Item 3"
  • מחזיר NodeList - אוסף של אלמנטים
  • אם אין תוצאות, מחזיר NodeList ריק (לא null)
  • ה-NodeList שמוחזר הוא סטטי - אם ה-DOM משתנה, הרשימה לא מתעדכנת

getElementsByClassName ו-getElementsByTagName

שיטות ישנות יותר שעדיין בשימוש:

<div class="card">Card 1</div>
<div class="card">Card 2</div>
<p class="card">Card 3</p>
// get elements by class name (no dot!)
const cards = document.getElementsByClassName("card");
console.log(cards); // HTMLCollection(3) [div, div, p]

// get elements by tag name
const divs = document.getElementsByTagName("div");
console.log(divs); // HTMLCollection(2) [div, div]

ההבדל בין NodeList ל-HTMLCollection

זה הבדל חשוב:

const nodeList = document.querySelectorAll(".card");     // NodeList
const htmlCollection = document.getElementsByClassName("card"); // HTMLCollection

// NodeList has forEach
nodeList.forEach(item => console.log(item)); // works

// HTMLCollection does NOT have forEach
// htmlCollection.forEach(item => console.log(item)); // ERROR!

// convert HTMLCollection to array if you need forEach
Array.from(htmlCollection).forEach(item => console.log(item)); // works
[...htmlCollection].forEach(item => console.log(item)); // also works

הבדל נוסף - HTMLCollection היא חיה (live):

const liveList = document.getElementsByClassName("card"); // live
const staticList = document.querySelectorAll(".card"); // static

console.log(liveList.length);   // 3
console.log(staticList.length); // 3

// add a new card to the DOM
const newCard = document.createElement("div");
newCard.className = "card";
document.body.appendChild(newCard);

console.log(liveList.length);   // 4 - automatically updated!
console.log(staticList.length); // 3 - stays the same
  • ברוב המקרים, עדיף להשתמש ב-querySelector ו-querySelectorAll כי הם יותר גמישים

ניווט ב-DOM - DOM navigation

אפשר לנווט בין אלמנטים דרך קשרי המשפחה שלהם בעץ:

<div id="parent">
    <h2>Title</h2>
    <p>First paragraph</p>
    <p>Second paragraph</p>
    <span>Last child</span>
</div>
const parent = document.getElementById("parent");

// children - all child elements
console.log(parent.children); // HTMLCollection [h2, p, p, span]
console.log(parent.children.length); // 4

// first and last child element
console.log(parent.firstElementChild); // <h2>
console.log(parent.lastElementChild);  // <span>

// navigate from child to parent
const h2 = parent.firstElementChild;
console.log(h2.parentElement); // <div id="parent">

// navigate between siblings
const firstP = h2.nextElementSibling;
console.log(firstP); // <p>First paragraph</p>

const secondP = firstP.nextElementSibling;
console.log(secondP); // <p>Second paragraph</p>

console.log(secondP.previousElementSibling); // <p>First paragraph</p>

שימו לב: יש גם מאפיינים בלי "Element" בשם - firstChild, nextSibling וכו'. אלה מחזירים את כל סוגי הצמתים (כולל טקסט ורווחים). כמעט תמיד נעדיף את הגרסה עם "Element":

עם Element (עדיף) בלי Element (כל הצמתים)
parentElement parentNode
children childNodes
firstElementChild firstChild
lastElementChild lastChild
nextElementSibling nextSibling
previousElementSibling previousSibling

closest ו-matches

שתי מתודות שימושיות מאוד:

element.closest

מחפש את ההורה הקרוב ביותר (כולל האלמנט עצמו) שמתאים לסלקטור:

<div class="card">
    <div class="card-body">
        <button class="btn">Click me</button>
    </div>
</div>
const btn = document.querySelector(".btn");

// find the closest parent that matches
console.log(btn.closest(".card-body")); // <div class="card-body">
console.log(btn.closest(".card"));      // <div class="card">
console.log(btn.closest(".nonexistent")); // null

// closest checks the element itself too
console.log(btn.closest(".btn")); // the button itself
  • שימושי מאוד כשעובדים עם אירועים ורוצים למצוא הורה מסוים
  • מחזיר null אם אף הורה לא מתאים

element.matches

בודק אם אלמנט מתאים לסלקטור CSS:

<div class="card active" id="card-1">Content</div>
const card = document.getElementById("card-1");

console.log(card.matches(".card"));         // true
console.log(card.matches(".active"));       // true
console.log(card.matches(".card.active"));  // true
console.log(card.matches("#card-1"));       // true
console.log(card.matches("div"));           // true
console.log(card.matches(".inactive"));     // false

שינוי אלמנטים - modifying elements

אחרי שמצאנו אלמנט, אפשר לשנות אותו בהרבה דרכים.

textContent מול innerText מול innerHTML

שלוש דרכים לגשת לתוכן של אלמנט:

<div id="example">
    <p>Hello <span style="display: none;">hidden</span> World</p>
</div>
const el = document.getElementById("example");

// textContent - all text, including hidden elements
console.log(el.textContent); // "Hello hidden World"

// innerText - only visible text (respects CSS)
console.log(el.innerText); // "Hello World"

// innerHTML - the raw HTML string
console.log(el.innerHTML); // '<p>Hello <span style="display: none;">hidden</span> World</p>'

מתי להשתמש במה

const container = document.getElementById("container");

// textContent - for plain text (safe, fast)
container.textContent = "Just plain text";

// innerHTML - for HTML content (be careful with user input!)
container.innerHTML = "<h2>Title</h2><p>Paragraph</p>";

// innerText is rarely used - textContent is usually better
  • textContent - הכי בטוח והכי מהיר, משתמשים בו לטקסט רגיל
  • innerHTML - כשצריך להכניס HTML, אבל מסוכן עם קלט ממשתמשים (התקפות XSS)
  • innerText - מחשב מה באמת נראה על המסך, יותר איטי

שינוי סגנונות - element.style

אפשר לשנות CSS ישירות על אלמנט דרך המאפיין style:

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

// set inline styles
box.style.backgroundColor = "lightblue";
box.style.color = "navy";
box.style.padding = "20px";
box.style.border = "2px solid blue";
box.style.borderRadius = "10px";
box.style.fontSize = "18px";
box.style.textAlign = "center";

שימו לב לכלל החשוב: שמות CSS עם מקף הופכים ל-camelCase ב-JavaScript:

CSS JavaScript
background-color backgroundColor
font-size fontSize
border-radius borderRadius
text-align textAlign
margin-top marginTop
z-index zIndex
// reading current inline style
console.log(box.style.backgroundColor); // "lightblue"

// removing a style - set to empty string
box.style.backgroundColor = "";

// setting multiple styles at once using cssText
box.style.cssText = "color: red; font-size: 24px; padding: 10px;";
// WARNING: cssText replaces ALL inline styles
  • element.style מגדיר רק inline styles (כמו style="..." ב-HTML)
  • הוא לא מראה סגנונות שבאים מ-CSS classes או stylesheets
  • כדי לראות את הסגנון המחושב (הסופי) של אלמנט:
// get the computed (final) style of an element
const computedStyle = getComputedStyle(box);
console.log(computedStyle.color);
console.log(computedStyle.fontSize);
console.log(computedStyle.display);

classList - ניהול מחלקות CSS

הדרך הנכונה לשנות עיצוב היא בדרך כלל דרך CSS classes, לא דרך inline styles. ה-classList מאפשר לנו לנהל את ה-classes של אלמנט:

<div id="box" class="card">Content</div>
const box = document.getElementById("box");

// add a class
box.classList.add("active");
// <div class="card active">

// add multiple classes at once
box.classList.add("highlighted", "large");
// <div class="card active highlighted large">

// remove a class
box.classList.remove("highlighted");
// <div class="card active large">

// toggle - add if missing, remove if present
box.classList.toggle("active");
// <div class="card large"> (active was removed)

box.classList.toggle("active");
// <div class="card large active"> (active was added back)

// check if a class exists
console.log(box.classList.contains("card")); // true
console.log(box.classList.contains("hidden")); // false

// replace one class with another
box.classList.replace("large", "small");
// <div class="card active small">

// list all classes
console.log(box.classList); // DOMTokenList ["card", "active", "small"]
console.log(box.classList.length); // 3

למה classList עדיף על inline styles

/* in your CSS file */
.card {
    border: 1px solid #ddd;
    border-radius: 8px;
    padding: 20px;
}

.card.active {
    border-color: blue;
    box-shadow: 0 0 10px rgba(0, 0, 255, 0.2);
}

.card.error {
    border-color: red;
    background-color: #fff0f0;
}
// clean and simple - just toggle classes
const card = document.querySelector(".card");

// activate
card.classList.add("active");

// show error
card.classList.remove("active");
card.classList.add("error");

// much better than:
// card.style.borderColor = "red";
// card.style.backgroundColor = "#fff0f0";
// card.style.boxShadow = "...";
  • כל העיצוב מוגדר ב-CSS (במקום אחד)
  • ב-JavaScript רק מחליפים classes
  • יותר קל לתחזק ולשנות

תכונות - attributes

אפשר לקרוא ולשנות תכונות HTML:

<a id="link" href="https://google.com" target="_blank" class="external">Google</a>
<img id="photo" src="cat.jpg" alt="A cute cat" width="300">
const link = document.getElementById("link");

// getAttribute - read any attribute
console.log(link.getAttribute("href")); // "https://google.com"
console.log(link.getAttribute("target")); // "_blank"
console.log(link.getAttribute("class")); // "external"

// setAttribute - set or create an attribute
link.setAttribute("href", "https://bing.com");
link.setAttribute("title", "Go to Bing");

// hasAttribute - check if attribute exists
console.log(link.hasAttribute("target")); // true
console.log(link.hasAttribute("download")); // false

// removeAttribute - remove an attribute
link.removeAttribute("target");

const photo = document.getElementById("photo");

// direct property access (common attributes)
console.log(photo.src); // full URL: "http://localhost/cat.jpg"
console.log(photo.alt); // "A cute cat"
console.log(photo.width); // 300

// change attributes directly
photo.src = "dog.jpg";
photo.alt = "A cute dog";
photo.width = 500;

גישה ישירה מול getAttribute

לרוב התכונות אפשר לגשת ישירות כ-property של האלמנט:

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

// these are usually the same
console.log(link.href);                   // "https://google.com" (full URL)
console.log(link.getAttribute("href"));   // "https://google.com" (as written)

// for id and className
console.log(link.id);        // same as getAttribute("id")
console.log(link.className); // same as getAttribute("class")
// note: the property is "className", not "class" (class is a reserved word in JS)

תכונות data - data attributes

תכונות data-* מאפשרות לנו לשמור מידע מותאם אישית על אלמנטים:

<div class="user-card"
     data-user-id="42"
     data-role="admin"
     data-last-login="2024-01-15">
    John Doe
</div>
const card = document.querySelector(".user-card");

// access via dataset (camelCase!)
console.log(card.dataset.userId);    // "42"
console.log(card.dataset.role);      // "admin"
console.log(card.dataset.lastLogin); // "2024-01-15"

// set new data attributes
card.dataset.status = "active";
// adds data-status="active" to the element

// delete a data attribute
delete card.dataset.lastLogin;
// removes data-last-login from the element

שימו לב לכלל ההמרה: data-user-id ב-HTML הופך ל-dataset.userId ב-JavaScript (camelCase, בלי data-).

HTML JavaScript
data-user-id dataset.userId
data-role dataset.role
data-last-login dataset.lastLogin
data-item-count dataset.itemCount

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

<input id="name-input" type="text" value="John" disabled>
<input id="agree-checkbox" type="checkbox" checked>
<button id="submit-btn" disabled>Submit</button>
<div id="secret" hidden>Secret content</div>
const nameInput = document.getElementById("name-input");
const checkbox = document.getElementById("agree-checkbox");
const submitBtn = document.getElementById("submit-btn");
const secret = document.getElementById("secret");

// value - get or set the input value
console.log(nameInput.value); // "John"
nameInput.value = "Jane";

// disabled - enable or disable
console.log(nameInput.disabled); // true
nameInput.disabled = false; // enables the input

// checked - for checkboxes and radio buttons
console.log(checkbox.checked); // true
checkbox.checked = false; // unchecks it

// hidden - show or hide an element
console.log(secret.hidden); // true
secret.hidden = false; // shows the element

// enable the button
submitBtn.disabled = false;

דוגמה מעשית - כרטיס פרופיל

נשלב את כל מה שלמדנו בדוגמה אחת:

<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
    <meta charset="UTF-8">
    <title>Profile Card</title>
    <style>
        .card {
            width: 300px;
            border: 2px solid #ddd;
            border-radius: 12px;
            padding: 20px;
            font-family: Arial, sans-serif;
            text-align: center;
        }
        .card.vip { border-color: gold; background-color: #fffde7; }
        .card img { width: 100px; height: 100px; border-radius: 50%; }
        .hidden { display: none; }
        .btn { padding: 8px 16px; cursor: pointer; margin: 5px; }
    </style>
</head>
<body>
    <div class="card" id="profile" data-user-id="42" data-role="member">
        <img id="avatar" src="default-avatar.png" alt="avatar">
        <h2 id="username">John Doe</h2>
        <p id="bio">Web developer from Tel Aviv</p>
        <p id="role-badge" class="hidden">VIP Member</p>
        <button class="btn" id="upgrade-btn">Upgrade to VIP</button>
        <button class="btn" id="edit-btn">Edit Profile</button>
    </div>

    <script>
        const card = document.getElementById("profile");
        const username = document.getElementById("username");
        const bio = document.getElementById("bio");
        const badge = document.getElementById("role-badge");
        const upgradeBtn = document.getElementById("upgrade-btn");
        const editBtn = document.getElementById("edit-btn");
        const avatar = document.getElementById("avatar");

        // upgrade to VIP
        upgradeBtn.addEventListener("click", function() {
            // change data attribute
            card.dataset.role = "vip";

            // add VIP styling
            card.classList.add("vip");

            // show the badge
            badge.classList.remove("hidden");

            // change button
            upgradeBtn.textContent = "Already VIP";
            upgradeBtn.disabled = true;
            upgradeBtn.style.opacity = "0.5";
        });

        // edit profile
        editBtn.addEventListener("click", function() {
            const newName = prompt("Enter new name:");
            if (newName) {
                username.textContent = newName;
            }

            const newBio = prompt("Enter new bio:");
            if (newBio) {
                bio.textContent = newBio;
            }
        });

        // log some info
        console.log("User ID:", card.dataset.userId);
        console.log("Role:", card.dataset.role);
        console.log("Has VIP class:", card.classList.contains("vip"));
        console.log("Avatar src:", avatar.getAttribute("src"));
        console.log("Username is closest to card:",
            username.closest(".card") === card);
    </script>
</body>
</html>

הדוגמה הזו משתמשת ב:
- getElementById ו-querySelector לבחירת אלמנטים
- textContent לשינוי טקסט
- classList.add, classList.remove לניהול classes
- dataset לעבודה עם data attributes
- disabled ו-style לשינוי מצב ועיצוב
- closest לבדיקת קשרי הורה
- getAttribute לקריאת תכונות

סיכום

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

מתודה מחזיר מתי להשתמש
getElementById("id") אלמנט / null כשיש id ספציפי
querySelector("css") אלמנט / null כשצריך את הראשון שמתאים
querySelectorAll("css") NodeList כשצריך את כולם
getElementsByClassName HTMLCollection (live) פחות נפוץ, אבל קיים
getElementsByTagName HTMLCollection (live) פחות נפוץ, אבל קיים
element.closest("css") אלמנט / null חיפוש הורה
element.matches("css") true/false בדיקה אם מתאים

שינוי תוכן

מאפיין שימוש
textContent טקסט רגיל (בטוח)
innerHTML תוכן HTML (זהירות)
innerText טקסט נראה (איטי)

שינוי עיצוב

  • element.style.property - inline styles (camelCase)
  • element.classList - ניהול CSS classes (עדיף)
  • getComputedStyle(element) - קריאת הסגנון הסופי

תכונות

  • getAttribute, setAttribute, hasAttribute, removeAttribute
  • element.dataset - תכונות data-*
  • גישה ישירה: element.id, element.className, element.src, element.href
  • מצב: element.value, element.checked, element.disabled, element.hidden