Наблюдайте мутации на целевом узле, который еще не существует

Возможно ли наблюдать мутации на узле DOM, который еще не существует?

Пример:

Мое приложение создает div в какой-то момент: <div id="message" data-message-content="foo" data-message-type="bar" />,

Я хочу наблюдать за созданием и изменением этого div.

var mutationObserver = new MutationObserver(function(mutations){
  // Some code to handle the mutation.
});

mutationObserver.observe(
    document.querySelector('#message'),
        { 
            attributes: true, 
            subtree: true, 
            childList: true, 
            characterData: false 
        }
    );
);

Прямо сейчас это возвращает ошибку, так как #message имеет значение null (div еще не создан).

Failed to execute 'observe' on 'MutationObserver': parameter 1 is not of type 'Node'.

Очевидное решение - наблюдать за body и проверьте, является ли какая-либо из мутаций созданием div#Message, но это кажется плохой идеей / или, возможно, плохой для производительности.

1 ответ

Решение

Можно наблюдать только существующий узел.

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

function waitForAddedNode(params) {
    new MutationObserver(function(mutations) {
        var el = document.getElementById(params.id);
        if (el) {
            this.disconnect();
            params.done(el);
        }
    }).observe(params.parent || document, {
        subtree: !!params.recursive,
        childList: true,
    });
}

Использование:

waitForAddedNode({
    id: 'message',
    parent: document.querySelector('.container'),
    recursive: false,
    done: function(el) {
        console.log(el);
    }
});

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

  • По возможности соблюдайте непосредственные родители будущего узла (subtree: false)
  • Используйте getElementById, getElementsByTagName и getElementsByClassName внутри обратного вызова MutationObserver, избегайте querySelector и особенно чрезвычайно медленного querySelectorAll.
  • Если querySelectorAll абсолютно неизбежен при обратном вызове MutationObserver, сначала выполните проверку querySelector, в среднем такая комбинация будет намного быстрее.
  • Не используйте методы Array, такие как forEach, filter и т. Д., Для которых требуются обратные вызовы внутри обратного вызова MutationObserver, потому что в Javascript вызов функции является дорогостоящей операцией по сравнению с классическим for (var i=0 ....) цикл, и обратный вызов MutationObserver может запускаться 100 раз в секунду с десятками, сотнями или тысячами addedNodes в каждой партии мутаций на сложных современных страницах.
  • Не используйте медленные петли ES2015, такие как for (v of something) внутри обратного вызова MutationObserver, если только вы не перекомпилируете и результирующий код будет работать так же быстро, как классический for петля.
Другие вопросы по тегам