Как в observer следить за определёнными объектами?

Есть вот такая конструкция:

<div class="wrap">
  <div class="adv">...</div>
  <div class="coup">...</div>
  <div class="news">...</div>
  <div class="coup">...</div>
  <div class="adv">...</div>
  <div class="coup">...</div>
</div>

Содержимое всех блоков меняется. Подскажите, как следить только за блоками с классом coup? Я нашла в интернете статью https://developer.mozilla.org/ru/docs/Web/API/MutationObserver/MutationObserver и там есть callback, но я так и не поняла, как его заполнить:

***
switch(mutation.type) {
      case 'childList':
        /* One or more children have been added to and/or removed
           from the tree; see mutation.addedNodes and
           mutation.removedNodes */
        break;
***

Я предположила, что должна разместить после case "childList": классы, которые мне нужны. Я попыталась сделать так: case 'childList': [".coup"] но ничего не вышло. Или я ошибаюсь и это не та статья? Подскажите, как следить только за определёнными элементами?


Ответы (1 шт):

Автор решения: Spatz

Возможны два варианта выборочного мониторинга:

  • подключить обсервер только к интересующим нас элементам,
  • подключить обсервер к общему предку и проверять в обработчике значение параметра mutation.target

Приведу пример для первого варианта:

function callback(mutationList, observer) {
  mutationList.forEach((mutation) => {
    switch (mutation.type) {
      case 'childList':
        log(`изменилась структура элемента .${mutation.target.className}`)
        break
      case 'attributes':
        log(`изменились атрибуты элемента .${mutation.target.className}`)
        break
    }
  })
}

const options = {
  childList: true,
  attributes: true,
  subtree: true // на всю глубину (false - только один уровень иерархии)
}
const observer = new MutationObserver(callback)

document.querySelectorAll(".coup").forEach(el =>
  observer.observe(el, options))

// дальше пошла мишура для демонстрации

document.querySelector('#add-to-coup').addEventListener('click', e => {
  document.querySelectorAll('.coup').forEach(el => {
    const child = document.createElement('div')
    child.innerHTML = '-- coup\'s child'
    el.appendChild(child)
  })
})

document.querySelector('#add-to-adv').addEventListener('click', e => {
  document.querySelectorAll('.adv').forEach(el => {
    const child = document.createElement('div')
    child.innerHTML = '-- adv\'s child'
    el.appendChild(child)
  })
})

document.querySelector('#change-coup').addEventListener('click', e => {
  document.querySelectorAll('.coup').forEach(el => {
    el.style.color = el.style.color === 'red' ? 'inherit' : 'red'
  })
})

document.querySelector('#change-adv').addEventListener('click', e => {
  document.querySelectorAll('.adv').forEach(el => {
    el.style.color = el.style.color === 'red' ? 'inherit' : 'red'
  })
})

function log(msg) {
  const item = document.createElement('li')
  item.innerHTML = msg
  document.querySelector('#log').appendChild(item)
}
  <button id="add-to-adv">добавить к .adv</button>
  <button id="add-to-coup">добавить к .coup</button>
  <button id="change-adv">изменить .adv</button>
  <button id="change-coup">изменить .coup</button>
  <ol style="width: 80vw; height: 100px; overflow-y: scroll;" id="log"></ol>
  <div class="wrap">
    <div class="adv">adv</div>
    <div class="coup">coup</div>
    <div class="news">news</div>
    <div class="coup">coup</div>
    <div class="adv">adv</div>
    <div class="coup">coup</div>
  </div>

Конкретные изменения (что именно добавлено или удалено) передаются в обработчик через свойства параметра mutation addedNodes и deletedNodes. Вот пример их использования:

function callback(mutationList, observer) {
  mutationList.forEach((mutation) => {
    switch (mutation.type) {
      case 'childList':
        mutation.addedNodes.forEach(el => {
          if (el.className === 'coup') {
            log('добавлен .coup')
          }
        })
        break
      case 'attributes':
        break
    }
  })
}

const options = {
  childList: true,
  attributes: false,
  subtree: false
}
const observer = new MutationObserver(callback)

observer.observe(document.querySelector(".wrap"), options)

document.querySelector('#add-new-coup').addEventListener('click', e => {
  const child = document.createElement('div')
  child.className = 'coup'
  child.innerHTML = 'new coup'
  document.querySelector('.wrap').appendChild(child)
})

document.querySelector('#add-new-adv').addEventListener('click', e => {
  const child = document.createElement('div')
  child.className = 'adv'
  child.innerHTML = 'new adv'
  document.querySelector('.wrap').appendChild(child)
})

function log(msg) {
  const item = document.createElement('li')
  item.innerHTML = msg
  document.querySelector('#log').appendChild(item)
}
  <button id="add-new-adv">добавить новый .adv</button>
  <button id="add-new-coup">добавить новый .coup</button>
  <ol style="width: 80vw; height: 100px; overflow-y: scroll;" id="log"></ol>
  <div class="wrap">
    <div class="adv">adv</div>
    <div class="coup">coup</div>
    <div class="news">news</div>
  </div>

→ Ссылка