Изменить элементы сразу после их отображения (не после полной загрузки страницы) в скрипте greasemonkey?
У меня есть этот сценарий. Он применяется на страницах фильма RottenTomatoes и изменяет 3 элемента
(1 видимый текст и 2 текста внутри подсказок).
В настоящее время (из-за greasemonkey's @run-at document-end
) он изменяет элементы только после полной загрузки страницы.
Кроме того, во многих случаях страницы RottenTomates задерживают загрузку, до 20 секунд (!),
так что это дополнительная задержка в моем сценарии.
Это вызывает две вещи:
- задержка отображения измененного видимого текста, и это,
- если навести указатель мыши на любую из всплывающих подсказок до полной загрузки страницы, то после загрузки она, вероятно, будет содержать только исходный текст без моего добавления или только с моим добавлением.
Чтобы увидеть это, установите скрипт, а затем посетите эту типичную целевую страницу.
Страницы RottenTomatoes загружают различный контент через XHR (как я видел в Firefox Netowork Monitor),
но 3 элемента (которые я хочу изменить) отображаются сразу, а не после полной загрузки страницы.
Я пытался использовать MutationObserver
следить за тем, чтобы конкретное текстовое значение появилось на экране, но, похоже, оно не работает. Его структура такова:
var target = selector_for_element_containing_text ; // the selector is: document.querySelector('.audience-info > div:nth-child(1)');
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
modifyElements();
});
});
var config = { attributes: true, childList: true, characterData: true, subtree: true };
observer.observe(target, config);
function modifyElements(){ // This is just the current code of my script
// modify element 1
// modify element 2
// modify element 3
}
Как я могу изменить элементы сразу после их отображения?
1 ответ
Заставьте скрипт работать на
document-start
добавив этот код в скрипт метаблока:.............. // @run-at document-start .............. // ==/UserScript==
Теперь, когда скрипт выполняется, в документе ничего нет, поэтому мы прикрепим наблюдателя к корню документа и отсканируем добавленные узлы для элемента контейнера.
.audience-info
:var observer = new MutationObserver(function(mutations) { for (var i=0; i<mutations.length; i++) { var mutationAddedNodes = mutations[i].addedNodes; for (var j=0; j<mutationAddedNodes.length; j++) { var node = mutationAddedNodes[j]; if (node.classList && node.classList.contains("audience-info")) { node.firstElementChild.innerHTML = node.firstElementChild.innerHTML .replace(/[\d.]+/g, function(m) { return 2 * m }); // don't hog resources any more as we've just done what we wanted observer.disconnect(); return; } } } }); observer.observe(document, {childList: true, subtree: true});
Когда вызывается обозреватель, всплывающие подсказки уже присутствуют в дереве документа, поэтому вы можете просто переместить код из функции "загрузить" в обозреватель до того, как
return
ничего не меняя.
NB. Лучше сделать наблюдателя максимально быстрым, особенно с помощью простого for
-loops вместо обратных вызовов функций из-за накладных расходов на их вызов, что может стать проблемой на медленном ПК / устройстве при открытии очень сложной страницы, которая генерирует тысячи (довольно распространенный случай) или сотни тысяч мутаций (крайне редко, но все же!). И отключите его, как только работа сделана.
PS С функцией setMutationHandler код наблюдателя будет:
// @require https://greasyfork.org/scripts/12228/code/setMutationHandler.js
// ==/UserScript==
setMutationHandler(document, '.audience-info div:first-child', function(nodes) {
this.disconnect();
nodes.forEach(function(n) {
n.innerHTML = n.innerHTML.replace(/[\d.]+/g, function(m) { return 2*m });
});
});