Javascript-用户脚本在执行代码技术之前要等待页面加载?

我正在编写一个Greasemonkey用户脚本,并且希望该页面完全完成加载后才能执行特定代码,因为它返回了我想要显示的div计数。

问题是,该特定页面有时需要一点时间才能加载所有内容。

我试过了setTimeout(function() { }, 600);$(window).load(function(){ });包装器。 但是,似乎没有一个对我有用,尽管我可能错误地使用了它们。

我所能做的最好是使用一个setTimeout(function() { }, 600);,尽管它并不总是可靠的,但它可以工作。

在Greasemonkey中使用哪种最佳技术来确保在页面完成加载后将执行特定代码?

7个解决方案
53 votes

Greasemonkey(通常)没有jQuery。 所以常见的方法是使用

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

在您的用户脚本中

devnull69 answered 2019-10-07T11:58:21Z
45 votes

这是一个普遍的问题,正如您已经说过的那样,仅等待页面加载是不够的-因为AJAX可以并且确实会在那之后改变事情。

对于这些情况,存在一个标准的(实用)鲁棒实用程序。 这是waitForKeyElements()实用程序。

像这样使用它:

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

请提供目标网页的确切详细信息,以获取更具体的示例。

Brock Adams answered 2019-10-07T11:59:03Z
23 votes

从Greasemonkey 3.6(2015年11月20日)开始,元数据键@run-at支持新值document-idle。只需将其放在您的Greasemonkey脚本的元数据块中:

// @run-at      document-idle

该文档描述如下:

该脚本将在页面和所有资源(图像,样式表等)加载并且页面脚本已运行之后运行。

Leviathan answered 2019-10-07T11:59:42Z
10 votes

将脚本包装在waitForKeyElements("elementtowaitfor", functiontocall)中对我来说从来没有失败过。

也许您的页面已经完成,但是仍然有一些ajax内容正在加载。

如果是这样,那么Brock Adams的这段不错的代码可以帮助您:
[https://gist.github.com/raw/2625891/waitForKeyElements.js]

我通常用它来监视回发中出现的元素。

像这样使用它:waitForKeyElements("elementtowaitfor", functiontocall)

RASG answered 2019-10-07T12:00:56Z
3 votes

如果您想操纵节点,例如获得节点的价值或更改样式,则可以使用此功能等待这些节点

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

然后使用async&await

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

或使用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
})()

这是一个示例icourse163_enhance

bilabila answered 2019-10-07T12:01:51Z
2 votes

Brock的回答很好,但是为了完整起见,我想提供另一种解决AJAX问题的方法。 由于他的脚本还使用attributes定期检查(300毫秒),因此它无法立即响应。

如果需要立即响应,则可以使用attributes侦听DOM更改,并在元素创建后立即对其进行响应

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

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

尽管由于attributes会在每个DOM更改上触发,但是如果DOM更改非常频繁或您的情况需要很长时间才能评估,则这可能会很慢。

另一个用例是,如果您不查找任何特定元素,而只是等待页面停止更改。 您也可以将其与attributes结合使用来等待。

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
}

这种方法用途广泛,您还可以侦听属性和文本更改。 只需在选项中将attributescharacterData设置为true

observer.observe(document, {childList: true, attributes: true, characterData: true, subtree: true});
goweon answered 2019-10-07T12:02:55Z
1 votes

为了检测XHR是否完成了在网页中的加载,它会触发一些功能。我是从如何使用JavaScript在Chrome的控制台中存储“ XHR完成加载”消息中得到的? 它是真实的作品。

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

但是,如果页面中有很多XHR,我不知道如何过滤确定的XHR。

另一个方法是waitForKeyElements(),它很好。[https://gist.github.com/BrockA/2625891]
有供Greasemonkey使用的样品。在同一页面上多次运行Greasemonkey脚本?

Dave B answered 2019-10-07T12:03:45Z
translate from https://stackoverflow.com:/questions/12897446/userscript-to-wait-for-page-to-load-before-executing-code-techniques