Domanda Greasemonkey: attendi che la pagina venga caricata prima di eseguire le tecniche del codice


Sto scrivendo un codice utente Greasemonkey e voglio che un codice specifico venga eseguito quando la pagina completa completamente il caricamento, poiché restituisce un conteggio div che voglio visualizzare.

Il problema è che questa pagina in particolare richiede un po 'prima che tutto si carichi.

Ho provato, documento $(function() { }); e $(window).load(function(){ }); involucri. Tuttavia, nessuno sembra funzionare per me, anche se potrei applicarli male.

Il meglio che posso fare è usare a setTimeout(function() { }, 600); che funziona, anche se non sempre affidabile.

Qual è la tecnica migliore da utilizzare in Greasemonkey per garantire che il codice specifico venga eseguito al termine del caricamento della pagina?


44
2017-10-15 14:09


origine


risposte:


Greasemonkey (di solito) non ha jQuery. Quindi l'approccio comune è da usare

window.addEventListener('load', function() {
    // your code here
}, false);

all'interno del tuo userscript


45
2017-10-15 14:38



Questo è un problema comune e, come hai detto, l'attesa del caricamento della pagina non è sufficiente, dal momento che AJAX può modificare le cose molto dopo.

Esiste un'utilità standard (ish) robusta per queste situazioni. Suo il waitForKeyElements() utilità.

Usalo in questo modo:

// ==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
}

Fornisci i dettagli esatti della tua pagina di destinazione per un esempio più specifico.


34
2017-10-15 15:51



A partire da Greasemonkey 3.6 (20 novembre 2015) la chiave dei metadati @run-at supporta il nuovo valore document-idle. Inseriscilo semplicemente nel blocco dei metadati del tuo script Greasemonkey:

// @run-at      document-idle

Il documentazione lo descrive come segue:

Lo script verrà eseguito dopo la pagina e tutte le risorse (immagini, fogli di stile, ecc.) Vengono caricate e gli script di pagina sono stati eseguiti.


14
2018-01-15 23:04



avvolgendo i miei script in $(window).load(function(){ }) mai fallito per me.

forse la tua pagina è finita, ma c'è ancora del contenuto di ajax che viene caricato.

se questo è il caso, questo bel pezzo di codice da Brock Adams posso aiutarti:
https://gist.github.com/raw/2625891/waitForKeyElements.js

di solito lo uso per monitorare gli elementi che appaiono su postback.

usalo in questo modo: waitForKeyElements("elementtowaitfor", functiontocall)


9
2017-10-15 14:43



Se vuoi manipolare i nodi come ottenere il valore dei nodi o cambiare stile, puoi aspettare questi nodi usando questa funzione

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()
})

quindi utilizzare 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
})

o usare 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
})()

Ecco un esempio icourse163_enhance


1
2018-03-28 14:21



La risposta di Brock è buono, ma mi piacerebbe offrire un'altra soluzione al problema AJAX, per completezza. Anche dal suo script setInterval() per controllare periodicamente (300 ms), non può rispondere istantaneamente.

Se è necessario rispondere immediatamente, è possibile utilizzare MutationObserver() per ascoltare le modifiche DOM e rispondere ad esse non appena viene creato l'elemento

(new MutationObserver(check)).observe(document, {childList: true, subtree: true});

function check(changes, observer) {
    if(document.querySelector('#mySelector')) {
        observer.disconnect();
        // code
    }
}

Anche se da allora check() si accende su ogni singola modifica DOM, questo può essere lento se il DOM cambia molto spesso o la tua condizione richiede molto tempo per essere valutata.

Un altro caso d'uso è se non stai cercando alcun elemento specifico, ma stai solo aspettando che la pagina smetta di cambiare. Puoi combinarlo con setTimeout() aspettare anche questo.

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
}

Questo metodo è così versatile che puoi anche ascoltare modifiche agli attributi e al testo. Basta impostare attributes e characterData a truenelle opzioni

observer.observe(document, {childList: true, attributes: true, characterData: true, subtree: true});

0
2017-11-21 06:41



Per rilevare se l'XHR ha terminato il caricamento nella pagina Web, attiva alcune funzioni. Ho capito Come faccio a utilizzare JavaScript per archiviare i messaggi "XHR finiti di caricare" nella console in Chrome? e funziona davvero.

    //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.
    //https://stackoverflow.com/questions/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;
    }

Ma se ci sono molti XHR nella pagina, non ho idea di come filtrare il XHR definito.

Un altro metodo è waitForKeyElements () che è bello. https://gist.github.com/BrockA/2625891
C'è un esempio per l'uso di Greasemonkey. Esegui script Greasemonkey sulla stessa pagina, più volte?


0
2018-04-02 06:01