Блог веб разработки статьи | видеообзоры | исходный код

Блог веб разработки статьи | видеообзоры | исходный код

webfanat вконтакте webfanat youtube

mutationObserver api

mutationObserver api

Доброго времени суток дорогие друзья! Сегодня рассмотрим интересное api mutationObserver. С помощью него можно отслеживать динамическое изменение dom-элементов(тегов). Это может быть полезно если вы захотите выполнить какое то действие при изменении определенного элемента с учетом изменений его содержимого или провести обычный мониторинг(отладку кода). Итак, поехали!

Рассмотрим пример:

<h1>Заголовок </h1>
<script>
    var element = document.querySelector('h1');

    var callback = function(mutations, observer) {
      mutations.forEach(function(mutation) {
        console.log(mutation, observer);
      });
    }

    const mutationObserver = new MutationObserver(callback);

    const config = {
      attributes: true,
      characterData: true,
      childList: true,
      subtree: true,
      attributeOldValue: true,
      characterDataOldValue: true,
    };
    
  mutationObserver.observe(element, config)
</script>

Здесь был создан обычный заголовок h1 на который было повешено отслеживание изменений через mutationObserver. Само api инициализируется через класс "MutationObserver" в качестве аргумента он принимает функцию "callback", та в свою очередь возвращает информацию об изменениях в консоль браузера. Для того чтобы запустить отслеживание изменений необходимо вызвать у класса MutationObserver метод observe() и передать в него два параметра. Первый параметр это элемент, изменения которого мы хотим отслеживать, второй это объект с конфигурациями. В нашем случае активированы практически все конфигурации mutationObserver api, мы каждую из них рассмотрим по ходу. Если по какой то причине вы захотите прервать отслеживание изменений у элемента, то можно вызвать метод disconnect().

mutationObserver.disconnect();

Данный метод останавливает отслеживание у элемента.

Теперь переходим к рассмотрению перехвата самих изменений элемента! Для простоты тестирования я просто открою консоль браузера на странице с вышеуказанным кодом и буду по ходу писать код.

Попробую изменить содержимое h1.

document.querySelector('h1').innerText = 'заголовок h1';

В результате в консоль будет выведен объект с общей информацией и объект 'MutationObserver'. Нас интересует первое! В общем объекте есть ключ 'type' в нашем случае он будет равняться 'childList'. Обратите внимание что название 'childList' есть в нашей конфигурации и представляет собой свойство которому было задано значение true(то есть активировано). Так вот эта конфигурация по сути включает возможность отслеживания изменения контента(содержимого) внутри элемента. Если ее не указать или поставить значение 'false', то изменения зафиксировано не будет. Аналогично и со всеми другими конфигурациями(attributes, characterData, subtree, attributeOldValue, characterDataOldValue) которые мы рассмотрим далее.

Далее попробуем добавить элемент в h1.

document.querySelector('h1').innerHTML = 'заголовок <span>h3</span>';

Здесь мы добавили элемент span, попробуем изменить его содержимое.

document.querySelector('h1 span').innerHTML = 'h1';

Заметьте что здесь у нас сработал перехват изменения элемента span, хотя на него мы отслеживание не вешали. Это произошло благодаря конфигурации "subtree: true", которая позволяет отслеживать изменение дочерних узлов(элементов) главного элемента.

Идем далее! Помимо содержимого можно отслеживать динамическое изменение атрибутов. Делается это с помощью двух конфигураций: "attributes: true" - включение отслеживания изменений атрибута, "characterDataOldValue: true" - старое значение атрибута после обновления.

Пример, добавим класс "active".

document.querySelector('h1').classList.add('active')

После отработки будет выведена информация по изменению атрибута, обратите внимание на значение "oldValue"(старое значение), оно равно null. Это потому что до этого у нас не существовало никаких классов у элемента. Если мы добавим новый класс, к примеру 'h1'.

document.querySelector('h1').classList.add('h1');

Теперь значение свойства "oldValue" будет равно 'active'. Я думаю общую логику вы поняли. Для атрибутов есть еще дополнительная конфигурация "attributeFilter" которая в качестве значения принимает массив с названиями атрибутов изменения которых мы хотим отслеживать.

Пример:

const config = {
  attributes: true,
  characterData: true,
  childList: true,
  subtree: true,
  attributeOldValue: true,
  characterDataOldValue: true,
  attributeFilter: ['id', 'contenteditable'] 
};

Здесь мы добавили еще одну конфигурацию "attributeFilter" c помощью которой можно отслеживать изменения только атрибутов 'id' и 'contenteditable'.

Давайте добавим новый атрибут 'contenteditable'.

document.querySelector('h1').setAttribute('contenteditable', 'true');

Кто не знает, атрибут contenteditable позволяет производить динамическое редактирование текста внутри указанного элемента. Он понадобится чтобы протестировать последние две конфигурации: "characterData: true" - динамическое редактирование текста и "characterDataOldValue: true" - старое значение редактируемого текста.

После того как установили атрибут contenteditable можно отредактировать текст внутри элемента. В процессе редактирования в консоль будет выводится информация о новых изменениях внутри элемента + "oldValue" старое значение до изменения.

Для более полного понимания как все работает я написал следующий код:

var element = document.querySelector('h1');

function childList(list){
  console.log("Изменено содержимое элемента", list.target);
  for(var elem of list.removedNodes){
    console.log("Удален узел ",  elem);
  }
  for(var elem of list.addedNodes){
    console.log("Добавлен узел ",elem);
  }
}

function attributes(list){
  console.log('Изменен атрибут ' + list.attributeName + " у элемента ", list.target);
  if(list.oldValue !== null){
      console.log('Старое значение: ' + list.oldValue);
  }
  console.log('Новое значение: ' + list.target.getAttribute(list.attributeName));

}
function characterData(list){
  console.log('Переписано значение "' + list.target.data + '" в "' + list.oldValue+'"');
}
var callback = function(mutations, observer) {
  mutations.forEach(function(mutation) {
    if(mutation.type === 'childList'){
      childList(mutation);
    }
     else if(mutation.type === 'attributes'){
      attributes(mutation);
    }
    else if(mutation.type === 'characterData'){
      characterData(mutation);
    }
  });
}
const mutationObserver = new MutationObserver(callback);

const config = {
  attributes: true,
  characterData: true,
  childList: true,
  subtree: true,
  attributeOldValue: true,
  characterDataOldValue: true,
 // attributeFilter: ['id', 'contenteditable']
};
mutationObserver.observe(element, config);

Здесь с помощью дополнительных функций выводится конкретная информация по изменениям внутри элемента h1. Вы можете поменять элемент h1 на любой другой или повесить отслеживание на все элементы.

var element = document.documentElement;

С помощью данного селектора вешаем отслеживание на корневой элемент root(html). И при наличии конфигурации "subtree: true" можно будет отслеживать изменение всех дочерних элементов тега html.

На этом у меня все. Надеюсь данная статья была для вас полезна и познавательна! Не забывайте подписываться на группу Вконтакте для получения уведомлений о выходе новых статей и переходите на мой канал Youtube.

Всем добра и процветания! Пока.

Оцените статью:

Статьи

Разработки

Комментарии

В данном разделе пока нет комментариев!

Реклама

Запись экрана

Данное расширение позволяет записывать экран и выводит видео в формате webm