Изменить элементы сразу после их отображения (не после полной загрузки страницы) в скрипте 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 ответ

Решение
  1. Заставьте скрипт работать на document-start добавив этот код в скрипт метаблока:

    ..............
    // @run-at        document-start
    ..............
    // ==/UserScript==
    
  2. Теперь, когда скрипт выполняется, в документе ничего нет, поэтому мы прикрепим наблюдателя к корню документа и отсканируем добавленные узлы для элемента контейнера. .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 });
    });
});
Другие вопросы по тегам