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

Полное руководство по методам манипуляции DOM

DOM (Document Object Model) — это критически важный аспект веб-разработки, который позволяет создавать динамичные и интерактивные веб-страницы. В этом руководстве рассматриваются лучшие практики, методы оптимизации производительности и способы клонирования узлов, которые помогут вам эффективно манипулировать DOM.

Лучшие практики манипуляции DOM

Минимизируйте прямой доступ к DOM

Доступ к DOM может быть медленным, так как это может заставить браузер заново вычислять макет и перерисовывать элементы. Чтобы минимизировать прямой доступ к DOM:

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

Оптимизируйте обработку событий

Подключайте обработчики событий эффективно:

  • Используйте делегирование событий, чтобы уменьшить количество слушателей событий.
  • Избегайте подключения слишком большого количества слушателей событий непосредственно к элементам.

Очищайте неиспользуемые элементы

Удаляйте элементы, которые больше не нужны, чтобы освободить память и повысить производительность:

  • Используйте методы removeChild или remove для удаления элементов из DOM.

Минимизация перерасчетов макета и перерисовок

Что такое Reflows и Repaints?

  • Reflows (перерасчет макета) происходят, когда макет части страницы изменяется, заставляя браузер заново вычислять позиции и размеры элементов.
  • Repaints (перерисовка) происходят, когда визуальное отображение элементов изменяется без влияния на макет (например, изменение цвета).

Методы минимизации Reflows и Repaints

Группировка изменений

Группируйте несколько изменений вместе, чтобы избежать повторяющихся перерасчетов макета и перерисовок:


html
<!DOCTYPE html>
<html>
<head>
    <title>Batching Changes</title>
</head>
<body>
    <div id="content">Original Content</div>
    <button id="update">Update Content</button>

    <script>
        document.getElementById('update').addEventListener('click', () => {
            const content = document.getElementById('content');
            content.style.display = 'none'; // Hide element to batch changes
            content.innerHTML = 'Updated Content';
            content.style.display = 'block'; // Show element after updates
        });
    </script>
</body>
</html>

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

Используйте CSS-классы для изменений

Применяйте CSS-изменения с помощью классов, а не путем прямого управления стилями:


html
<!DOCTYPE html>
<html>
<head>
    <title>Use CSS Classes</title>
    <style>
        .hidden { display: none; }
        .highlight { color: red; font-weight: bold; }
    </style>
</head>
<body>
    <div id="content">Hello World</div>
    <button id="toggle">Toggle Highlight</button>

    <script>
        document.getElementById('toggle').addEventListener('click', () => {
            const content = document.getElementById('content');
            content.classList.toggle('highlight');
        });
    </script>
</body>
</html>

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

Использование DocumentFragment для повышения производительности

Что такое DocumentFragment?

DocumentFragment — это легковесный контейнер, используемый для хранения группы узлов. Он не является частью основного дерева DOM, поэтому изменения в нем не вызывают перерасчетов макета и перерисовок.

INFO

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

Пример использования DocumentFragment


html
<!DOCTYPE html>
<html>
<head>
    <title>Document Fragments</title>
</head>
<body>
    <div id="list"></div>
    <button id="populate">Populate List</button>

    <script>
        document.getElementById('populate').addEventListener('click', (event) => {
            const fragment = document.createDocumentFragment();
            for (let i = 1; i <= 25; i++) {
                const item = document.createElement('div');
                item.textContent = `Item ${i}`;
                fragment.appendChild(item);
            }
            document.getElementById('list').appendChild(fragment);
            event.target.disabled = true; // Disable the button
        });
    </script>
</body>
</html>

Этот пример создает 25 элементов div и добавляет их в DocumentFragment. Только после того, как все элементы будут добавлены в фрагмент, он сам добавляется в DOM за одну операцию. Этот подход минимизирует перерасчеты макета и перерисовки, обновляя DOM только один раз.

Клонирование узлов

Метод cloneNode()

Метод cloneNode() используется для создания копии узла. Он может клонировать сам узел или узел вместе с его дочерними элементами.

Клонирование узла без дочерних элементов


html
<!DOCTYPE html>
<html>
<head>
    <title>Cloning Nodes</title>
</head>
<body>
    <div id="original">Original Node</div>
    <button id="clone">Clone Node</button>

    <script>
        document.getElementById('clone').addEventListener('click', () => {
            const original = document.getElementById('original');
            const clone = original.cloneNode(false); // Clone without children
            clone.id = 'clone';
            clone.textContent = 'Cloned Node';
            document.body.appendChild(clone);
        });
    </script>
</body>
</html>

Этот пример демонстрирует, как клонировать узел без его дочерних элементов с помощью метода cloneNode(false). Клонированный узел скопирует атрибуты и текстовое содержимое исходного узла, но не его дочерние узлы.

Клонирование узла с дочерними элементами


html
<!DOCTYPE html>
<html>
<head>
    <title>Cloning Nodes with Children</title>
</head>
<body>
    <div id="original">
        Original Node
        <span>Child Node</span>
    </div>
    <button id="clone">Clone Node with Children</button>

    <script>
        document.getElementById('clone').addEventListener('click', () => {
            const original = document.getElementById('original');
            const clone = original.cloneNode(true); // Clone with children
            clone.id = 'clone';
            document.body.appendChild(clone);
        });
    </script>
</body>
</html>

Этот пример демонстрирует, как клонировать узел вместе с его дочерними элементами с помощью метода cloneNode(true). Клонированный узел будет включать содержимое исходного узла и все его дочерние узлы.

Заключение

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

Практика

Какие из следующих методов используются для манипуляции DOM в JavaScript?

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

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