לדלג לתוכן

3.1 מה זה ה DOM פתרון

פתרון - מה זה ה-DOM

פתרון תרגיל 1

<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
    <meta charset="UTF-8">
    <title>Document Investigation</title>
</head>
<body>
    <h1>Hello World</h1>

    <script>
        // print document properties
        console.log("Title:", document.title); // "Document Investigation"
        console.log("URL:", document.URL); // the file path or URL
        console.log("Body:", document.body); // the body element
        console.log("Head:", document.head); // the head element

        // change the title
        document.title = "Changed by JavaScript!";
        // the browser tab now shows "Changed by JavaScript!"
    </script>
</body>
</html>

פתרון תרגיל 2

<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
    <meta charset="UTF-8">
    <title>Window Investigation</title>
</head>
<body>
    <h1>Window Object</h1>

    <script>
        // window dimensions
        console.log("Width:", window.innerWidth);
        console.log("Height:", window.innerHeight);

        // current URL
        console.log("URL:", window.location.href);

        // var vs let on window
        var myVar = "I am var";
        let myLet = "I am let";

        console.log("var on window:", window.myVar); // "I am var"
        console.log("let on window:", window.myLet); // undefined

        // show alert
        window.alert("Hello from JavaScript!");
    </script>
</body>
</html>

var נשמר על ה-window כי משתנים גלובליים שמוגדרים עם var הופכים למאפיינים של ה-window. לעומת זאת, let ו-const לא נשמרים על ה-window.

פתרון תרגיל 3

עץ ה-DOM:

document
  └── html (element)
       ├── head (element)
       │    └── title (element)
       │         └── "My Website" (text)
       └── body (element)
            ├── header (element)
            │    ├── h1 (element)
            │    │    └── "Welcome" (text)
            │    └── nav (element)
            │         ├── a [href="/"] (element)
            │         │    └── "Home" (text)
            │         └── a [href="/about"] (element)
            │              └── "About" (text)
            └── main (element)
                 ├── p (element)
                 │    └── "Hello World" (text)
                 └── <!-- todo: add more content --> (comment)

שימו לב שיש גם צמתי טקסט של רווחים בין אלמנטים (whitespace text nodes), אבל אלה לא משמעותיים ובדרך כלל מתעלמים מהם.

פתרון תרגיל 4

<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
    <meta charset="UTF-8">
    <title>DOM vs HTML</title>
</head>
<body>
    <h1 id="title">Original Title</h1>
    <p id="message">Original message.</p>
    <div id="container"></div>

    <script>
        // 1. change h1 text
        document.getElementById("title").textContent = "Modified Title";

        // 2. change body background
        document.body.style.backgroundColor = "lightblue";

        // 3. create new element and add to container
        const newParagraph = document.createElement("p");
        newParagraph.textContent = "I was added by JS!";
        document.getElementById("container").appendChild(newParagraph);
    </script>
</body>
</html>
  • ב-DevTools Elements נראה: את ה-h1 עם הטקסט "Modified Title", את style על ה-body, ואת הפסקה החדשה בתוך ה-container
  • ב-View Page Source נראה: את ה-HTML המקורי - "Original Title", בלי style על ה-body, ו-container ריק
  • זה ההבדל - DevTools מראה את ה-DOM (המצב החי), ו-View Source מראה את ה-HTML המקורי

פתרון תרגיל 5

קובץ a.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <script>
        const el = document.getElementById("title");
        console.log("File A:", el); // null!
    </script>
</head>
<body>
    <h1 id="title">Hello</h1>
</body>
</html>

התוצאה: null - כי ה-script רץ לפני שה-body נבנה.

קובץ b.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
</head>
<body>
    <h1 id="title">Hello</h1>
    <script>
        const el = document.getElementById("title");
        console.log("File B:", el); // the h1 element
    </script>
</body>
</html>

התוצאה: האלמנט h1 - כי ה-script רץ אחרי שה-h1 כבר נבנה.

קובץ c.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <script src="c.js" defer></script>
</head>
<body>
    <h1 id="title">Hello</h1>
</body>
</html>

קובץ c.js:

const el = document.getElementById("title");
console.log("File C:", el); // the h1 element

התוצאה: האלמנט h1 - כי defer גורם לסקריפט לרוץ אחרי שה-DOM מוכן.

שימו לב: defer על inline script (בלי src) לא עובד - הדפדפן מתעלם מ-defer במקרה הזה. צריך להשתמש ב-defer רק עם קובץ חיצוני.

פתרון תרגיל 6

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Events Test</title>
    <script>
        document.addEventListener("DOMContentLoaded", function() {
            console.log("DOM is ready!", new Date().toLocaleTimeString());

            // change the status text
            document.getElementById("status").textContent =
                "DOM is ready, waiting for images...";
        });

        window.addEventListener("load", function() {
            console.log("Everything loaded!", new Date().toLocaleTimeString());

            // change the status text
            document.getElementById("status").textContent =
                "Everything loaded!";
        });
    </script>
</head>
<body>
    <h1>Loading Test</h1>
    <img src="https://picsum.photos/2000/2000" alt="large image">
    <p id="status">Loading...</p>
</body>
</html>
  • DOMContentLoaded מופיע ראשון כי הוא נורה ברגע שה-HTML נטען
  • load מופיע אחרי כמה שניות, כשהתמונה הגדולה סיימה להיטען
  • הפרש הזמנים תלוי בגודל התמונה ובמהירות האינטרנט

פתרון תרגיל 7

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Node Types</title>
</head>
<body>
    <div id="content">
        <h1>Title</h1>
        <!-- this is a comment -->
        <p>Paragraph text</p>
        Some loose text
    </div>

    <script>
        const content = document.getElementById("content");

        console.log("Using childNodes:");
        for (const node of content.childNodes) {
            console.log(
                "Type:", node.nodeType,
                "| Name:", node.nodeName,
                "| Value:", node.nodeValue?.trim() || "(none)"
            );
        }

        console.log("---");
        console.log("Using children (elements only):");
        for (const child of content.children) {
            console.log("Tag:", child.tagName);
        }
    </script>
</body>
</html>

הפלט יהיה משהו כזה:

Using childNodes:
Type: 3 | Name: #text | Value: (none)       // whitespace
Type: 1 | Name: H1 | Value: (none)          // element
Type: 3 | Name: #text | Value: (none)       // whitespace
Type: 8 | Name: #comment | Value: this is a comment  // comment
Type: 3 | Name: #text | Value: (none)       // whitespace
Type: 1 | Name: P | Value: (none)           // element
Type: 3 | Name: #text | Value: Some loose text       // text
---
Using children (elements only):
Tag: H1
Tag: P

  • childNodes מחזיר את כל סוגי הצמתים (אלמנטים, טקסט, הערות)
  • children מחזיר רק צמתי אלמנט
  • שימו לב לרווחים (whitespace) בין האלמנטים - הם נספרים כצמתי טקסט ב-childNodes

תשובות לשאלות

  1. DOM מול HTML - ה-HTML הוא קוד המקור שכתבנו. ה-DOM הוא מבנה עץ חי שהדפדפן בונה מה-HTML. JavaScript יכול לשנות את ה-DOM, מה שמשנה את מה שהמשתמש רואה, אבל לא את קובץ ה-HTML המקורי.

  2. document מול window - ה-window הוא האובייקט הגלובלי של הדפדפן, ומייצג את חלון הדפדפן. ה-document הוא אובייקט שנמצא בתוך ה-window (window.document) ומייצג את המסמך (הדף) עצמו.

  3. script ב-head - כי הדפדפן קורא את ה-HTML מלמעלה למטה. כש-script ב-head רץ, ה-body עדיין לא נוצר, אז האלמנטים לא קיימים בזיכרון ונקבל null.

  4. DOMContentLoaded מול load - DOMContentLoaded נורה כשה-HTML נטען וה-DOM נבנה. load נורה רק כשהכל נטען - כולל תמונות, CSS, פונטים ומשאבים חיצוניים. DOMContentLoaded תמיד קורה ראשון.

  5. defer מול async - שניהם מורידים את הסקריפט ברקע. defer מריץ רק אחרי שה-DOM מוכן ושומר על סדר הסקריפטים. async מריץ מיד כשההורדה נגמרה, בלי קשר לסדר או למצב ה-DOM.

  6. children מול childNodes - children מחזיר רק צמתי אלמנט (תגיות HTML). childNodes מחזיר את כל סוגי הצמתים - כולל טקסט, הערות ורווחים.