Userscript to wait for page to load before executing code techniques?

前端 未结 7 1950
迷失自我
迷失自我 2020-11-27 10:24

I\'m writing a Greasemonkey user script, and want the specific code to execute when the page completely finishes loading since it returns a div count that I want to be displ

相关标签:
7条回答
  • 2020-11-27 11:03

    wrapping my scripts in $(window).load(function(){ }) never failed for me.

    maybe your page has finished, but there is still some ajax content being loaded.

    if that is the case, this nice piece of code from Brock Adams can help you:
    https://gist.github.com/raw/2625891/waitForKeyElements.js

    i usually use it to monitor for elements that appears on postback.

    use it like this: waitForKeyElements("elementtowaitfor", functiontocall)

    0 讨论(0)
  • 2020-11-27 11:13

    This is a common problem and, as you've said, waiting for the page load is not enough -- since AJAX can and does change things long after that.

    There is a standard(ish) robust utility for these situations. It's the waitForKeyElements() utility.

    Use it like 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
    }
    

    Give exact details of your target page for a more specific example.

    0 讨论(0)
  • 2020-11-27 11:13

    If you want to manipulate nodes like getting value of nodes or changing style, you can wait for these nodes using this function

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

    then use 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
    })
    

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

    Here is an example icourse163_enhance

    0 讨论(0)
  • 2020-11-27 11:20

    To detect if the XHR finished loading in the webpage then it triggers some function. I get this from How do I use JavaScript to store "XHR finished loading" messages in the console in Chrome? and it real works.

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

    But if there're many XHRs in the page, I have no idea how to filter the definite one XHR.

    Another method is waitForKeyElements() which is nice. https://gist.github.com/BrockA/2625891
    There's sample for Greasemonkey use. Run Greasemonkey script on the same page, multiple times?

    0 讨论(0)
  • 2020-11-27 11:21

    As of Greasemonkey 3.6 (November 20, 2015) the metadata key @run-at supports the new value document-idle. Simply put this in the metadata block of your Greasemonkey script:

    // @run-at      document-idle
    

    The documentation describes it as follows:

    The script will run after the page and all resources (images, style sheets, etc.) are loaded and page scripts have run.

    0 讨论(0)
  • 2020-11-27 11:22

    Greasemonkey (usually) doesn't have jQuery. So the common approach is to use

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

    inside your userscript

    0 讨论(0)
提交回复
热议问题