3.2 בחירת ושינוי אלמנטים פתרון
פתרון - בחירת ושינוי אלמנטים¶
פתרון תרגיל 1¶
// 1. select header by id
const header = document.getElementById("main-header");
console.log("Header:", header);
// 2. select active link
const activeLink = document.querySelector(".nav-link.active");
console.log("Active link:", activeLink.textContent);
// 3. select all nav links
const allLinks = document.querySelectorAll(".nav-link");
console.log("Number of links:", allLinks.length); // 4
// 4. select all cards and print their data-category
const cards = document.querySelectorAll(".card");
cards.forEach(function(card) {
console.log("Category:", card.dataset.category);
});
// 5. select external link using attribute selector
const externalLink = document.querySelector('a[href^="https"]');
console.log("External link:", externalLink.textContent);
// 6. find h2 of first card using DOM navigation
const firstCard = document.querySelector(".card");
const firstH2 = firstCard.firstElementChild;
console.log("First card title:", firstH2.textContent);
פתרון תרגיל 2¶
// 1. change h1 text
const title = document.getElementById("title");
title.textContent = "Changed Title";
// 2. change innerHTML of content
const content = document.getElementById("content");
content.innerHTML = `
<h2>New Subtitle</h2>
<p>First new paragraph.</p>
<p>Second new paragraph.</p>
`;
// 3. add a list to output
const output = document.getElementById("output");
output.innerHTML = `
<ul>
<li>Item One</li>
<li>Item Two</li>
<li>Item Three</li>
</ul>
`;
// 4. differences between textContent, innerHTML, innerText
console.log("textContent:", content.textContent);
// "New Subtitle First new paragraph. Second new paragraph."
console.log("innerHTML:", content.innerHTML);
// '<h2>New Subtitle</h2><p>First new paragraph.</p>...'
console.log("innerText:", content.innerText);
// "New Subtitle\nFirst new paragraph.\nSecond new paragraph."
textContentמחזיר את כל הטקסט בלי תגיות HTMLinnerHTMLמחזיר את ה-HTML הגולמי כמחרוזתinnerTextמחזיר את הטקסט הנראה, עם שבירות שורה כמו שהם מוצגים
פתרון תרגיל 3¶
const box = document.getElementById("box");
const btn = document.getElementById("style-btn");
btn.addEventListener("click", function() {
// 1. background color
box.style.backgroundColor = "lightcoral";
// 2. text color
box.style.color = "white";
// 3. border radius
box.style.borderRadius = "15px";
// 4. font size
box.style.fontSize = "20px";
// 5. box shadow
box.style.boxShadow = "5px 5px 20px rgba(0, 0, 0, 0.3)";
// 6. change button text
btn.textContent = "Done!";
// 7. disable button
btn.disabled = true;
});
פתרון תרגיל 4¶
const box = document.getElementById("box");
const btnRed = document.getElementById("btn-red");
const btnBlue = document.getElementById("btn-blue");
const btnRound = document.getElementById("btn-round");
const btnShadow = document.getElementById("btn-shadow");
const btnLarge = document.getElementById("btn-large");
const btnReset = document.getElementById("btn-reset");
btnRed.addEventListener("click", function() {
box.classList.add("red");
box.classList.remove("blue");
});
btnBlue.addEventListener("click", function() {
box.classList.add("blue");
box.classList.remove("red");
});
btnRound.addEventListener("click", function() {
box.classList.toggle("rounded");
});
btnShadow.addEventListener("click", function() {
box.classList.toggle("shadow");
});
btnLarge.addEventListener("click", function() {
box.classList.toggle("large");
});
btnReset.addEventListener("click", function() {
// remove all classes except "box"
box.className = "box";
// alternatively:
// box.classList.remove("red", "blue", "rounded", "shadow", "large");
});
פתרון תרגיל 5¶
const products = document.querySelectorAll(".product");
let totalInStock = 0;
products.forEach(function(product) {
const name = product.querySelector("h3").textContent;
const price = parseFloat(product.dataset.price);
const category = product.dataset.category;
const inStock = product.dataset.inStock === "true";
// 1. print product info
console.log(`${name} - $${price} - ${category} - In stock: ${inStock}`);
// 2. calculate total of in-stock products
if (inStock) {
totalInStock += price;
}
// 3. add class for out-of-stock products
if (!inStock) {
product.classList.add("out-of-stock");
}
// 4. add discounted attribute for expensive products
if (price > 100) {
product.dataset.discounted = "true";
}
});
// show total
const summary = document.getElementById("summary");
summary.textContent = "Total in stock: $" + totalInStock.toFixed(2);
פתרון תרגיל 6¶
// 1. get the table by id
const table = document.getElementById("users-table");
// 2. get tbody (second child of table: thead is first, tbody is second)
const tbody = table.children[1]; // or table.lastElementChild
// 3. get first row in tbody
const firstRow = tbody.firstElementChild;
// 4. print name of first user (first cell)
const firstName = firstRow.firstElementChild.textContent;
console.log("First user:", firstName); // "Alice"
// 5. iterate all rows and print names
let currentRow = tbody.firstElementChild;
while (currentRow) {
const name = currentRow.firstElementChild.textContent;
console.log("User:", name);
currentRow = currentRow.nextElementSibling;
}
// 6. change background of last row
const lastRow = tbody.lastElementChild;
lastRow.style.backgroundColor = "lightyellow";
פתרון תרגיל 7¶
// 1. select all delete buttons
const deleteButtons = document.querySelectorAll(".delete-btn");
// 2. for each button, find its parent card and print data-id
deleteButtons.forEach(function(btn) {
const card = btn.closest(".card");
console.log("Button belongs to card with id:", card.dataset.id);
});
// 3. check if each card is "featured"
const allCards = document.querySelectorAll(".card");
allCards.forEach(function(card) {
const isFeatured = card.matches(".featured");
const id = card.dataset.id;
console.log(`Card ${id} is featured: ${isFeatured}`);
});
// 4. from each delete button, find the cards-container
deleteButtons.forEach(function(btn) {
const container = btn.closest(".cards-container");
console.log("Found container:", container !== null); // true
});
פתרון תרגיל 8¶
const buttons = document.querySelectorAll(".theme-btn");
const title = document.getElementById("title");
const body = document.body;
buttons.forEach(function(btn) {
btn.addEventListener("click", function() {
const theme = btn.dataset.theme;
// 1. change body class to the selected theme
body.className = theme;
// 2. move active-theme class to clicked button
buttons.forEach(function(b) {
b.classList.remove("active-theme");
});
btn.classList.add("active-theme");
// 3. update title text
const themeName = theme.charAt(0).toUpperCase() + theme.slice(1);
title.textContent = "Theme: " + themeName;
// 4. save selected theme in data attribute
body.dataset.currentTheme = theme;
});
});
תשובות לשאלות¶
-
querySelector מול getElementById -
getElementByIdמחפש רק לפי id וזה קצת יותר מהיר.querySelectorמקבל כל סלקטור CSS ויותר גמיש. ברוב המקרים ההבדל בביצועים זניח, ואפשר להשתמש במה שנוח יותר. -
NodeList מול HTMLCollection - NodeList (שמוחזר מ-querySelectorAll) הוא סטטי ויש לו forEach. HTMLCollection (שמוחזר מ-getElementsByClassName) הוא חי (מתעדכן אוטומטית כשה-DOM משתנה) ואין לו forEach.
-
classList מול style - כי
classListמאפשר לנו להגדיר את כל העיצוב ב-CSS ולהחליף classes ב-JavaScript. זה יותר נקי, יותר קל לתחזוקה, ומאפשר שימוש חוזר.styleמגדיר inline styles שקשה יותר לנהל. -
textContent מול innerHTML -
textContentמחזיר ומגדיר טקסט רגיל בלי HTML.innerHTMLמחזיר ומגדיר HTML כמחרוזת, כולל תגיות.textContentבטוח מפני התקפות XSS, ו-innerHTMLעלול להיות מסוכן עם קלט ממשתמשים. -
closest מול matches -
closestמחפש הורה (כולל האלמנט עצמו) שמתאים לסלקטור, ומחזיר אלמנט או null.matchesרק בודק אם האלמנט עצמו מתאים לסלקטור, ומחזיר true/false.closestשימושי בטיפול באירועים כשרוצים למצוא הורה מסוים, ו-matchesשימושי לסינון.