Наблюдайте мутации на целевом узле, который еще не существует
Возможно ли наблюдать мутации на узле 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
петля.