Ich schreibe ein Greasemonkey-Benutzerskript und möchte, dass der spezifische Code ausgeführt wird, wenn die Seite vollständig geladen ist, da er eine Div-Anzahl zurückgibt, die angezeigt werden soll.
Das Problem ist, dass diese bestimmte Seite manchmal etwas dauert, bis alles geladen ist.
Ich habe versucht, zu dokumentieren $(function() { });
und zu $(window).load(function(){ });
verpacken. Allerdings scheint keiner für mich zu funktionieren, obwohl ich sie möglicherweise falsch anwende.
Das Beste, was ich tun kann, ist eine zu verwenden, setTimeout(function() { }, 600);
die funktioniert, obwohl sie nicht immer zuverlässig ist.
Was ist die beste Technik in Greasemonkey, um sicherzustellen, dass der spezifische Code ausgeführt wird, wenn die Seite vollständig geladen ist?
quelle
(function init(){var counter = document.getElementById('id-of-element');if (counter) { /* do something with counter element */ } else { setTimeout(init, 0);}})();
um kontinuierlich nach der Existenz des Elements zu suchen. Das ist die allgemeinste Lösung.@run-at
Werte, die enthaltendocument-idle
undcontext-menu
von Nutzen sein können. Es scheint auch , dass Greasemonkey ist Unterstützung Zugabe fürdocument-idle
obwohl es jetzt noch nicht dokumentiert worden.Antworten:
Greasemonkey hat (normalerweise) kein jQuery. Der übliche Ansatz ist also die Verwendung
window.addEventListener('load', function() { // your code here }, false);
in Ihrem Userscript
quelle
@require http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js
es Ihrem aktuellen Skript hinzufügen . Ich habe sie auch in das Vorlagenskript eingefügt, weil ich sie immer benutze. Auchthis.$ = this.jQuery = jQuery.noConflict(true);
um typische Konflikte zu vermeiden.Dies ist ein häufiges Problem, und wie Sie bereits gesagt haben, reicht es nicht aus, auf das Laden der Seite zu warten, da AJAX die Dinge noch lange danach ändern kann und tut.
Für diese Situationen gibt es ein standardmäßiges (ish) robustes Dienstprogramm. Es ist das
waitForKeyElements()
Dienstprogramm .Verwenden Sie es so:
// ==UserScript== // @name _Wait for delayed or AJAX page load // @include http://YOUR_SERVER.COM/YOUR_PATH/* // @require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js // @require https://gist.github.com/raw/2625891/waitForKeyElements.js // @grant GM_addStyle // ==/UserScript== /*- The @grant directive is needed to work around a major design change introduced in GM 1.0. It restores the sandbox. */ waitForKeyElements ("YOUR_jQUERY_SELECTOR", actionFunction); function actionFunction (jNode) { //-- DO WHAT YOU WANT TO THE TARGETED ELEMENTS HERE. jNode.css ("background", "yellow"); // example }
Geben Sie genaue Details Ihrer Zielseite für ein genaueres Beispiel an.
quelle
@grant GM_addStyle
wie gezeigt verwenden. Dafür ist es da.true
als drittes Argument angeben,waitForKeyElements
ob Ihr Code nur einmal ausgeführt werden sollAb Greasemonkey 3.6 (20. November 2015) unterstützt der Metadatenschlüssel
@run-at
den neuen Wertdocument-idle
. Fügen Sie dies einfach in den Metadatenblock Ihres Greasemonkey-Skripts ein:// @run-at document-idle
Die Dokumentation beschreibt es wie folgt:
quelle
waitForKeyElements
oder zu verwendenMutationObserver
.Brocks Antwort ist gut, aber ich möchte eine andere Lösung für das AJAX-Problem anbieten, die moderner und eleganter ist. Da sein Skript auch
setInterval()
zur regelmäßigen Überprüfung (300 ms) verwendet wird, kann es nicht sofort reagieren.Wenn Sie sofort reagieren müssen, können Sie
MutationObserver()
auf DOM-Änderungen warten und darauf reagieren, sobald das Element erstellt wurde(new MutationObserver(check)).observe(document, {childList: true, subtree: true}); function check(changes, observer) { if(document.querySelector('#mySelector')) { observer.disconnect(); // code } }
Obwohl seitdem
check()
bei jeder einzelnen DOM-Änderung ein Brand ausgelöst wird, kann dies langsam sein, wenn sich das DOM sehr häufig ändert oder die Bewertung Ihres Zustands lange dauert.Ein weiterer Anwendungsfall ist, wenn Sie nicht nach einem bestimmten Element suchen, sondern nur darauf warten, dass sich die Seite nicht mehr ändert. Sie können dies mit kombinieren
setTimeout()
, um auch darauf zu warten.var observer = new MutationObserver(resetTimer); var timer = setTimeout(action, 3000, observer); // wait for the page to stay still for 3 seconds observer.observe(document, {childList: true, subtree: true}); function resetTimer(changes, observer) { clearTimeout(timer); timer = setTimeout(action, 3000, observer); } function action(o) { o.disconnect(); // code }
Diese Methode ist so vielseitig, dass Sie auch auf Attribut- und Textänderungen achten können. Gerade gesetzt
attributes
undcharacterData
zutrue
in den Optionenobserver.observe(document, {childList: true, attributes: true, characterData: true, subtree: true});
quelle
Das Einpacken meiner Skripte ist
$(window).load(function(){ })
für mich nie gescheitert.Möglicherweise ist Ihre Seite fertig, aber es werden noch einige Ajax-Inhalte geladen.
In diesem Fall kann Ihnen dieser nette Code von Brock Adams helfen:
https://gist.github.com/raw/2625891/waitForKeyElements.js
Ich benutze es normalerweise, um nach Elementen zu suchen , die auf dem Postback erscheinen .
benutze es so:
waitForKeyElements("elementtowaitfor", functiontocall)
quelle
Wenn Sie Knoten bearbeiten möchten, z. B. den Wert von Knoten abrufen oder den Stil ändern möchten, können Sie mit dieser Funktion auf diese Knoten warten
const waitFor = (...selectors) => new Promise(resolve => { const delay = 500 const f = () => { const elements = selectors.map(selector => document.querySelector(selector)) if (elements.every(element => element != null)) { resolve(elements) } else { setTimeout(f, delay) } } f() })
dann benutze
promise.then
// scripts don't manipulate nodes waitFor('video', 'div.sbg', 'div.bbg').then(([video, loading, videoPanel])=>{ console.log(video, loading, videoPanel) // scripts may manipulate these nodes })
oder verwenden
async&await
//this semicolon is needed if none at end of previous line ;(async () => { // scripts don't manipulate nodes const [video, loading, videoPanel] = await waitFor('video','div.sbg','div.bbg') console.log(video, loading, video) // scripts may manipulate these nodes })()
Hier ist ein Beispiel icourse163_enhance
quelle
Um festzustellen, ob das Laden des XHR auf der Webseite abgeschlossen ist, wird eine Funktion ausgelöst. Ich erhalte dies von Wie verwende ich JavaScript, um "XHR fertig geladen" -Nachrichten in der Konsole in Chrome zu speichern? und es funktioniert wirklich.
//This overwrites every XHR object's open method with a new function that adds load and error listeners to the XHR request. When the request completes or errors out, the functions have access to the method and url variables that were used with the open method. //You can do something more useful with method and url than simply passing them into console.log if you wish. ///programming/43282885/how-do-i-use-javascript-to-store-xhr-finished-loading-messages-in-the-console (function() { var origOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function(method, url) { this.addEventListener('load', function() { console.log('XHR finished loading', method, url); display(); }); this.addEventListener('error', function() { console.log('XHR errored out', method, url); }); origOpen.apply(this, arguments); }; })(); function display(){ //codes to do something; }
Aber wenn die Seite viele XHRs enthält, habe ich keine Ahnung, wie die bestimmte XHR gefiltert werden soll.
Eine andere Methode ist waitForKeyElements (), was sehr schön ist. https://gist.github.com/BrockA/2625891
Es gibt ein Beispiel für die Verwendung von Greasemonkey. Führen Sie das Greasemonkey-Skript mehrmals auf derselben Seite aus?
quelle