Перейти к содержимому

Узлы DOM в JavaScript

Понимание DOM-узлов

Объектная модель документа (DOM) — это фундаментальное понятие в веб-разработке, выступающее в роли интерфейса между документами HTML и JavaScript. Когда веб-страница загружается, браузер создаёт DOM, преобразуя статический контент в динамический интерфейс, которым можно управлять программно. Это руководство посвящено DOM-узлам — базовым единицам этой структуры — и поможет вам освоить навыки для улучшения динамических веб-приложений.

Что такое DOM-узел?

Каждый компонент документа, такой как элементы, текст, атрибуты или комментарии, представлен в DOM как узел. Каждый узел — это объект, наследующийся от класса Node, который необходим для работы с документом.


javascript
<!DOCTYPE html>
<html>
<head>
    <title>DOM Nodes Example</title>
</head>
<body>
    <div id="example">
        <!-- This is a comment node -->
        <p>This is a text node within an element node.</p>
    </div>
    <script>
        let exampleDiv = document.getElementById('example');
        exampleDiv.style.border = '2px solid blue'; // Highlight the div element
        exampleDiv.style.padding = '10px';
    </script>
</body>
</html>

Пояснение: В этом примере мы обращаемся к div с идентификатором example и применяем CSS-стили, чтобы визуально выделить его. Это демонстрирует, как напрямую изменять свойства стиля узла-элемента, делая его более заметным на странице.

Разные типы DOM-узлов

Узлы в DOM классифицируются, чтобы упростить манипуляции с документом:

  • Узлы-элементы: Определяют структурные компоненты HTML-документов.
  • Текстовые узлы: Содержат текст внутри элементов.
  • Узлы-атрибуты: Связаны с атрибутами элементов.
  • Узлы-комментарии: Содержат комментарии внутри вашего HTML.

javascript
<!DOCTYPE html>
<html>
<head>
    <title>Node Types Interactive Example</title>
    <style>
        #info {
            border: 1px solid #ccc;
            padding: 10px;
            margin-bottom: 10px;
        }
        #output {
            border: 1px solid #ccc;
            padding: 10px;
        }
        button {
            cursor: pointer;
            margin-bottom: 10px;
        }
    </style>
</head>
<body>
    <div id="info">
        <!-- This is a comment node -->
        <p>Element node with a <span>child element node</span> and some text.</p>
    </div>
    <button onclick="displayNodeTypes()">Show Node Types</button>
    <div id="output">Node types will be displayed here.</div>
    <script>
        function displayNodeTypes() {
            const infoDiv = document.getElementById('info');
            const outputDiv = document.getElementById('output');
            outputDiv.innerHTML = '';  // Clear previous output
            const nodeTypes = [];

            // Iterate over all child nodes of the div
            infoDiv.childNodes.forEach(node => {
                let typeDescription = '';
                switch(node.nodeType) {
                    case Node.ELEMENT_NODE:
                        typeDescription = 'Element node: ' + node.tagName;
                        break;
                    case Node.TEXT_NODE:
                        // Trim text content and check if it's not empty
                        let textContent = node.textContent.trim();
                        if (textContent) {
                            typeDescription = 'Text node: "' + textContent + '"';
                        }
                        break;
                    case Node.COMMENT_NODE:
                        typeDescription = 'Comment node: "' + node.textContent.trim() + '"';
                        break;
                }

                // Only add non-empty descriptions
                if (typeDescription) {
                    nodeTypes.push(typeDescription);
                    const p = document.createElement('p');
                    p.textContent = typeDescription;
                    outputDiv.appendChild(p);
                }
            });

            // If no nodes are visible or found
            if (nodeTypes.length === 0) {
                outputDiv.textContent = 'No visible nodes found.';
            }
        }
    </script>
</body>
</html>

Этот HTML-документ демонстрирует, как определять и отображать разные типы DOM-узлов (например, узлы-элементы, текстовые и узлы-комментарии). Он включает стилизованный блок для отображения этих узлов, кнопку, которая запускает функцию JavaScript для анализа и перечисления этих узлов, а также область для вывода результатов. Функция JavaScript проверяет каждый узел в заданной части документа, классифицирует его и выводит его тип и детали.

Манипулирование DOM-узлами

Повышение интерактивности веб-сайтов требует уверенного владения манипуляциями с DOM. Вот как динамически изменять ваши веб-страницы.

Создание и добавление узлов

Добавление новых элементов динамически необходимо для интерактивных веб-сайтов:


javascript
<!DOCTYPE html>
<html>
<head>
    <title>Add Node Example</title>
</head>
<body>
    <button onclick="addNewParagraph()">Add Paragraph</button>
    <script>
        function addNewParagraph() {
            let newNode = document.createElement('p');
            newNode.textContent = 'This is a new paragraph.';
            document.body.appendChild(newNode);
        }
    </script>
</body>
</html>

Пояснение: Этот пример включает кнопку, которая при нажатии запускает функцию для создания нового элемента абзаца (<p>) и добавляет его в тело документа. Он демонстрирует, как JavaScript можно использовать для динамического добавления контента на страницу, что особенно полезно для приложений, которым нужно обновляться в реальном времени без перезагрузки страницы.

Удаление узлов

Удаление элементов из DOM:


javascript
<!DOCTYPE html>
<html>
<head>
    <title>Remove Node Example</title>
</head>
<body>
    <div id="container">
        <p id="toBeRemoved">This paragraph will be removed. <button onclick="removeParagraph()">Remove</button></p>
    </div>
    <script>
        function removeParagraph() {
            let parentNode = document.getElementById('container');
            let childNode = document.getElementById('toBeRemoved');
            parentNode.removeChild(childNode);
        }
    </script>
</body>
</html>

Пояснение: Этот скрипт наглядно демонстрирует удаление DOM-элемента с помощью кнопки, встроенной прямо в сам абзац. Метод removeChild() используется для удаления указанного элемента, показывая динамическое действие, инициированное пользователем, которое напрямую изменяет структуру документа.

Замена узлов

Замена узлов в DOM:


javascript
<!DOCTYPE html>
<html>
<head>
    <title>Replace Node Example</title>
</head>
<body>
    <div id="oldElement">This element will be replaced. <button onclick="replaceElement()">Replace</button></div>
    <script>
        function replaceElement() {
            let newNode = document.createElement('div');
            newNode.textContent = 'This is a replacement.';
            let oldNode = document.getElementById('oldElement');
            oldNode.parentNode.replaceChild(newNode, oldNode);
        }
    </script>
</body>
</html>

Пояснение: В этом интерактивном примере кнопка запускает замену существующего div на вновь созданный div. Это иллюстрирует метод replaceChild(), который особенно полезен в ситуациях, когда элемент нужно обновить в зависимости от действий пользователя или внешних событий, например при получении новых данных с сервера.

Лучшие практики и советы

  • Минимизируйте манипуляции с DOM: Частые обновления могут привести к проблемам с производительностью. Оптимизируйте, сокращая количество манипуляций.
  • Используйте DocumentFragment для массового добавления: Для добавления нескольких элементов сразу используйте DocumentFragment, чтобы минимизировать перерасчёты и повысить производительность.

INFO

Всегда обеспечивайте кроссбраузерную совместимость при работе с DOM. Тестирование в разных браузерах помогает предотвратить неожиданное поведение и обеспечивает единообразный пользовательский опыт.

Примеры DocumentFragment:

Как мы узнали выше, при добавлении нескольких элементов в DOM использование DocumentFragment может значительно повысить производительность. Создавая DocumentFragment и добавляя к нему элементы, мы уменьшаем количество необходимых перерасчётов и перерисовок, поскольку фрагмент не является частью живого DOM. После того как все элементы добавлены во фрагмент, сам фрагмент можно добавить в DOM одной операцией.


html
<!DOCTYPE html>
<html>
<head>
    <title>DocumentFragment Example</title>
</head>
<body>
    <div id="list-container">
        <h2>Item List</h2>
        <ul id="item-list">
            <!-- Items will be added here -->
        </ul>
        <button id="add-items">Add 100 Items</button>
    </div>

    <script>
        const itemList = document.getElementById('item-list');
        const addItemsButton = document.getElementById('add-items');

        addItemsButton.addEventListener('click', () => {
            // Create a DocumentFragment
            const fragment = document.createDocumentFragment();

            // Add 100 list items to the fragment
            for (let i = 1; i <= 100; i++) {
                const listItem = document.createElement('li');
                listItem.textContent = `Item ${i}`;
                fragment.appendChild(listItem);
            }

            // Append the fragment to the item list
            itemList.appendChild(fragment);
        });
    </script>
</body>
</html>
  • Мы начинаем с выбора элемента <ul>, куда будут добавляться новые элементы, и кнопки, которая будет запускать добавление.
  • Когда нажимается кнопка "Add 100 Items", мы создаём объект DocumentFragment.
  • Затем мы создаём 100 элементов <li> в цикле, задаём их текстовое содержимое и добавляем каждый из них в DocumentFragment.
  • Наконец, мы добавляем DocumentFragment в элемент <ul>. Поскольку во время этапа построения фрагмент не является частью живого DOM, такой подход минимизирует перерасчёты и перерисовки, повышая производительность.

Использование DocumentFragment особенно полезно, когда нужно сразу добавить в DOM большое количество элементов, поскольку это снижает накладные расходы, связанные с множественными перерасчётами и перерисовками, обеспечивая более плавные и быстрые обновления.

DOM-узлы vs DOM-деревья

DOM-узлы и DOM-деревья — связанные понятия, но они относятся к разным аспектам того, как структурирован и изменяется веб-документ:

  1. DOM-узлы: DOM-узел — это отдельный компонент внутри Объектной модели документа (DOM). Каждый элемент, текст, комментарий и атрибут в HTML- или XML-документе считается узлом. Узлы — это фундаментальные строительные блоки документа. Например, тег <h1>, текст внутри этого тега и даже атрибуты этого тега (например, class="title") — это отдельные узлы.
  2. DOM-дерево: DOM-дерево — это вся структура или иерархия узлов, организованных в документе. Это древовидное представление, показывающее, как все узлы в документе связаны друг с другом. Узлы в этом дереве имеют отношения родитель-потомок, как папки и файлы на вашем компьютере. Например, в HTML-документе узел <body> может быть родительским узлом, а несколько дочерних узлов, таких как <div>, <p> и <img>, представляют разные части веб-страницы.

Проще говоря, DOM-узел можно представить как одну точку или часть более крупной головоломки, а DOM-дерево — как всю головоломку целиком или полный набор связей между этими точками. DOM-дерево полезно для навигации и изменения структуры документа с помощью таких языков программирования, как JavaScript, поскольку оно позволяет разработчикам эффективно находить (выбирать), изменять или обновлять элементы внутри вложенной иерархии.

Заключение

Освоение DOM-узлов крайне важно для любого разработчика JavaScript, стремящегося создавать интерактивные, динамические веб-приложения. Эти примеры и пояснения дают чёткое понимание того, как эффективно работать с DOM, улучшая как пользовательский опыт, так и функциональность ваших веб-приложений.

Практика

Какие из следующих вариантов являются типами DOM-узлов в веб-документе?

Считаете ли это полезным?

Предпросмотр dual-run — сравните с маршрутами Symfony на продакшене.