3.2 בחירת ושינוי אלמנטים הרצאה
בחירת אלמנטים - selecting elements¶
כדי לעשות משהו עם אלמנט ב-DOM, קודם צריך למצוא אותו. יש כמה דרכים לבחור אלמנטים, ונלמד את כולן.
getElementById¶
הדרך הכי פשוטה - מחפש אלמנט לפי ה-id שלו:
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¶
שיטות ישנות יותר שעדיין בשימוש:
// 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¶
מחפש את ההורה הקרוב ביותר (כולל האלמנט עצמו) שמתאים לסלקטור:
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:
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¶
שלוש דרכים לגשת לתוכן של אלמנט:
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 של אלמנט:
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,removeAttributeelement.dataset- תכונות data-*- גישה ישירה:
element.id,element.className,element.src,element.href - מצב:
element.value,element.checked,element.disabled,element.hidden