DevGang
Авторизоваться

Лучшие практики манипулирования JS DOM – с примерами

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

Пользователь события DOMContentLoaded

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

Чтобы использовать DOMContentLoaded, добавьте в документ прослушиватель событий и прослушивайте событие DOMContentLoaded. Это помогает предотвратить любые проблемы, которые могут возникнуть при попытке манипулировать элементами, которые еще не отрисованы.

Пример:

document.addEventListener('DOMContentLoaded', function() {
  // Your DOM manipulation code goes here...
})

Кэширование выбранных элементов

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

const cachedElement = document.getElementById('exampleId')

Таким образом, вы можете ссылаться на переменные в любое время, когда захотите их использовать. Это помогает повысить производительность, поскольку сокращает ненужную работу.

Запрос родительских элементов вместо документа

Когда вы кэшируете элемент, вы также можете запросить его, чтобы выбрать любого из его потомков. Это может помочь повысить производительность, поскольку ограничивает область запроса и уменьшает количество запросов ко всему документу.

Пример:

<div id="parent">
    <p id="child">Example paragraph</p>
</div>
const parentElement = document.getElementById('parent')

// Options 1: Querying entire document ❌
const childFromDocument = document.getElementById('child') 

// Options 2: Query the parent element ✅
const childFromParent = document.querySelector('#child')

В приведенном выше примере представлена ​​простая разметка, содержащая элемент #parent div и .child paragraph. Тогда есть два варианта выбора дочернего элемента.

Технически оба варианта верны и выберут один и тот же элемент. Но разница заключается в объеме запроса.

Пример 1 запрашивает (или ищет) весь документ, чтобы найти и выбрать дочерний элемент. Это менее эффективно и даже необязательно, поскольку родительский элемент элемента, который вы собираетесь выбрать, уже кэширован.

Пример 2 сужает область запроса (или поиска), запрашивая только родительский элемент, а не весь документ. Вот почему он предпочтителен, потому что он более эффективен, особенно если документ большой.

Также обратите внимание, что для запроса родителя используется метод querySelector. Использование getElementById запроса к родителю не будет работать и приведет к ошибке.

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

Для стилизации элементов лучше использовать классы CSS, а не встроенные стили. Классы легко поддерживать по сравнению со встроенными стилями, которыми сложно управлять.

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

Пример:

.styledClass {
  color: red;
}
element.classList.add('styledClass')

В этом примере используется .add свойство classListдля добавления styledClass к элементу. Предполагая, что вы хотите удалить класс из элемента, вы можете легко сделать это, используя свойство .remove вместо add.

Используйте innerHTMLс осторожностью

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

По возможности используйте свойство innerText или textContentдля визуализации строк. Но если вам нужно использовать innerHTML, убедитесь, что вы используете его для вставки контента из надежных источников. Или очистите и проверьте предоставленный контент с помощью такой библиотеки, как DOMPurify.

Напишите читаемые прослушиватели событий

Часто вы передаете прослушивателям событий два аргумента. Первый — это событие, которое вы слушаете, а второй — обработчик события (функция, которая срабатывает при возникновении события).

Чтобы ваш код было легко читать и поддерживать, вы можете определить функцию обработчика событий вне прослушивателя событий. Затем вы можете вызвать его в прослушивателе четности, как в примере 1 ниже:

Example 1 ✅

MyElement.addEventListener('click', handleClick) 

function handleClick() { 
    // your logic goes here.. 
} 

// Example 2 ❌ 

myElement.addEventListener('click', function() { 
    // your logic goes here... 
})

Оба технически правильны и будут делать одно и то же. Но пример 1 предпочтительнее, потому что его легче читать. Кроме того, при необходимости вы можете повторно использовать функцию handleClick. Это поможет вам соблюдать принцип DRY (не повторяйте себя).

Используйте делегирование событий для обработки событий DOM

Делегирование событий — это когда вы прикрепляете прослушиватель событий к родительскому элементу для прослушивания событий его потомков. С помощью этого метода вы можете уменьшить количество прослушивателей событий, которые нужно включить в свой код.

Например, предположим, что у вас есть пять кнопок внутри родительского элемента div:

<div id="parent"> 
    <button id="btn-1">1st Button</button> 
    <button id="btn-2">2nd Button</button> 
    <button id="btn-3">3rd Button</button> 
    <button id="btn-4">4th Button</button> 
    <button id="btn-5">5th Button</button> 
</div>

Вы можете добавить прослушиватель событий к каждой из пяти кнопок, чтобы прослушивать нажатия. Или, используя делегирование событий, вы можете использовать одно событие только в родительском div:

const parentElement = document.getElementById('parent') 

parentElement.addEventListener('click', handleClick) 

function handleClick(event) { 
  alert(event.target.id) 
}

В этом примере событие делегируется родительскому элементу. И мы используем event.target.id, чтобы получить фактическую кнопку, которую нажал пользователь. Если вам интересно, вы можете запустить код на Stackblitz и посмотреть, как он работает.

Делегирование событий помогает сэкономить время и повысить производительность. Представьте себе, как этот метод может пригодиться при работе с большим количеством динамического контента.

Пакетное обновление DOM с помощью фрагмента

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

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

Пример без фрагмента:

const container = document.getElementById('container')

for (let i = 0; i < 1000; i++) { 
    const listItem = document.createElement('li')
    listItem.textContent = `Item ${i}`
    container.appendChild(listItem) 
}

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

Пример с фрагментом:

const container = document.getElementById('container') 
const fragment = document.createDocumentFragment()

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

container.appendChild(fragment)

Приведенный выше код добавляет listItem к fragment на каждой итерации цикла. Он добавляет дочерний элемент к container элементу только после завершения цикла. Это означает, что DOM обновляется только один раз, а не 1000 раз, как раньше.

Используйте метод stopPropagation

Метод stopPropagation управляет потоком событий в DOM. По умолчанию, когда событие происходит с элементом, оно всплывает (распространяется) через своих предков.

Такое поведение, связанное с распространением событий, иногда может привести к непредвиденным результатам. Этот stopPropagation метод предоставляет способ остановить распространение события на родителя и других предков.

Давайте рассмотрим ситуацию, когда у вас есть кнопка внутри родительского элемента div. И вы хотите обработать событие нажатия кнопки без регистрации щелчка по элементу div:

<div id="container">
    <button id="button">Click me</button>
</div>
const containerDiv = document.getElementById('container')
const buttonElement = document.getElementById('button')

containerDiv.addEventListener('click', handleDivClick)
buttonElement.addEventListener('click', handleBtnClick)

function handleDivClick() { 
    console.log('Div clicked')
} 

function handleBtnClick(event) { 
    event.stopPropagation()
    console.log('Button clicked')
} 

Без использования этого метода stopPropagation событие щелчка на кнопке также вызовет событие щелчка в родительском элементе div. Это означает, что оба обработчика событий будут запущены.

Но event.stopPropagation() строка в коде предотвратит запуск функции handleDivClick, когда пользователь нажмет кнопку.

Вы можете запустить код на Stackblitz, чтобы увидеть, как он работает. Закомментируйте строку с методом stopPropagation и увидите разницу.

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

Когда вы пишете тесты, вы создаете сценарии, имитирующие взаимодействие с пользователем или состояния приложения. Вы также убедитесь, что ваше приложение дает ожидаемые результаты.

Тестирование вашего кода манипуляции с DOM — лучшая практика, поскольку оно сделает ваш код надежным и простым в обслуживании. Это также дает вам уверенность в том, что ваш код ведет себя так, как ожидалось, даже если он развивается с течением времени, когда вы вносите изменения и добавляете функции.

Вы можете использовать платформы тестирования и библиотеки, доступные для JavaScript, такие как Jest, Mocha, Jasmine и другие, для автоматизации тестирования ваших приложений.

В следующем примере используется платформа Jest для проверки кода манипуляции DOM для добавления класса к элементу.

test('Adding a highlight class changes text color to red', () => {
    myElement.classList.add('highlight');
    expect(getComputedStyle(myElement).color).toBe('red');
});

Ожидается, что добавление класса highlight изменит цвет текста на красный. Если тест пройден, это означает, что ваш код манипуляции с DOM работает должным образом. Если нет, вам нужно будет разобраться, что не так, и устранить проблему.

Заключение

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

Источник:

#JavaScript #HTML
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу