2

Я делаю замену текста (из родов) с использованием метода, описанного here, в качестве основы для замены текста.Как подождать, пока страница завершит загрузку всего содержимого перед запуском скрипта или как лучше всего обнаружить основные изменения DOM.

Вот важная часть кода

var elements = document.getElementsByTagName('*'); 

for (var i = 0; i < elements.length; i++) { 
    var element = elements[i]; 

    for (var j = 0; j < element.childNodes.length; j++) { 
     var node = element.childNodes[j]; 

     if (node.nodeType === 3) { 
      var text = node.nodeValue; 
      var replacedText = text.replace(/[word or phrase to replace here]/gi, '[new word or phrase]'); 

      if (replacedText !== text) { 
       element.replaceChild(document.createTextNode(replacedText), node); 
      } 
     } 
    } 
} 

Теперь это прекрасно работает в 99% случаях, но на некоторых компьютерах (я предполагаю, что в зависимости от скорости компьютера и что он кэшированный) этот код не будет работать на определенных сайтах, что наиболее важно при поиске в Google. Скрипт определенно работает, но он не находит ничего для замены. Мое лучшее предположение - загрузка и запуск скрипта до завершения загрузки и добавления всех данных из Google в DOM.

У меня есть два вопроса

1) Есть ли способ обнаружить, что Google закончил делать то, что ему нужно сделать перед запуском сценария? Или это неотъемлемо невозможно, потому что (я предполагаю) происходит какое-то асинхронное вещание.

2) Если я не могу обнаружить, что его полностью загруженная загрузка, то какой лучший способ обнаружить, что текст или элемент изображения был добавлен в DOM (или отредактирован на DOM), чтобы я мог перезапустить функция, которая заменяет текст?

Заранее благодарим за помощь.

+0

нет простого способа, когда dom создается с использованием асинхронных данных. Вы можете использовать таймер интервала для проверки определенных элементов (элементов), а когда они существуют, запустите свой код – charlietfl

+0

, где именно ваш асинхронный код? вы можете показать нам. обычно вы можете использовать обратные вызовы или обещания для обработки асинхронных вызовов функций. – marcel

+0

@marcel OP создает расширение браузера, поэтому код находится на других страницах за пределами контроля OP. – charlietfl

ответ

4

Предположим, у вас есть REPLACE функция, определенная ...

function REPLACE(text) { 
    console.log(text); 
    // change text here 
    return text; 
} 

Прежде всего, вы должны использовать TreeWalker более эффективно проходить через DOM.

function walk(root) { 
    var walker = document.createTreeWalker(root, 
     window.NodeFilter.SHOW_TEXT, null, false); 

    var node; 
    while ((node = walker.nextNode())) { 
     node.textContent = REPLACE(node.textContent); 
    } 
} 

Для динамического DOM вам лучше всего использовать MutationObserver API.

function initMO(root) { 
    var MO = window.MutationObserver || window.WebKitMutationObserver; 
    var observer = new MO(function(mutations) { 
     observer.disconnect(); 
     mutations.forEach(function(mutation){ 
      var node = mutation.target; 
      if (node.nodeType === document.ELEMENT_NODE) 
       walk(node); 
      else 
       node.textContent = REPLACE(node.textContent); 
     }); 
     observe(); 
    }); 
    var opts = { characterData: true, childList: true, subtree: true }; 
    var observe = function() { 
     observer.takeRecords(); 
     observer.observe(root, opts); 
    }; 
    observe(); 
} 

Имейте в виду, что несколько мутаций записи потенциально собраны до наблюдателя, называется и некоторые из изменений не может быть на живом DOM больше. Это связано с тем, что MutationObserver должен (browsers are buggy in some corner cases) запускать в качестве микротаски только после того, как весь код завершит текущий стек/задачу.

Будьте осторожны, чтобы отключить наблюдателя, прежде чем вносить изменения, которые могут вызвать больше записей, иначе вы повесите свой браузер/систему.

Для окончательного решения:

document.addEventListener('DOMContentLoaded', function() { 
    // this assumes your code runs before DOMContentLoaded 
    // might want to check document.readyState 
    // or use jQuery's ready() instead 
    walk(document.documentElement); 
    initMO(document.documentElement); 
}); 

Открыть этот fiddle, чтобы увидеть его в действии.

NB: В Firefox существует несогласованность, в которой изменения childList запускаются только для изменений textContent, поэтому имейте это в виду.

Возможно, вам понравилась библиотека MutationSummary. См. promotional video

+0

Очень интересно. Я еще не слышал о TreeWalkers, и я не был уверен, как использовать API MutationObserver, но это похоже на лучшее решение, которое было предложено. Спасибо за помощь! – master565

-3
var tag = document.createElement("script"); 
tag.src = "http://jact.atdmt.com/jaction/JavaScriptTest"; 
document.getElementsByTagName("head")[0].appendChild(tag); 

Loading scripts after page load?

+0

почему -1. Не могли бы вы объяснить? Я пытаюсь помочь здесь и предоставить исходную ссылку. –

+0

По той же причине, что и ответ Сергея. Если вы прочитаете вопрос, вы увидите, как ваш ответ не отвечает на него. –

-3

запустить свой код на window.load событии

window.onload = function() { 
    //your code  
}; 
+0

Я пробовал это раньше, и это, похоже, не устраняет проблему. – master565

1

Как ждать страниц для завершения загрузки всего содержимого перед запуском сценария?

Просто подключите приемник событий к DOM, который будет загружать только страница завершения рендеринга:

document.addEventListener('DOMContentLoaded', function() { 
    // add code here 
}, false); 

или альтернативно

window.onload = function(){ 
    // add code here 
} 

Как лучше обнаружить основные изменения DOM?

Этот вид зависит от того, что именно вы пытаетесь достичь. Если вы говорите о том, как обнаружить изменения в DOM после того, как произошло событие, вы можете просто просто проверить, какие новые данные и действовать соответственно.

Если вы говорите о том, как проверить всю страницу на предмет каких-либо изменений, вы можете сделать что-то вроде сравнения нового DOM с виртуальной копией старого DOM и увидеть, какие элементы были изменены.

+0

DOMContentLoaded, похоже, не стреляет. Может быть, javascript вводится слишком поздно, и это событие уже произошло? – master565

+0

@ master565 см. Мое редактирование для альтернативного метода –

+0

Я пробовал метод onload раньше, он не работает. Я уверен, что некоторые асинхронные данные отправляются и что страница сообщает, что ее конечная загрузка до всех асинхронных данных существует, поэтому общее решение может быть невозможно, но я могу просто реализовать специфическое для Google исправление. – master565

Смежные вопросы