javascript 用户脚本等待页面加载前执行代码技术?

m3eecexj  于 2023-03-06  发布在  Java
关注(0)|答案(7)|浏览(132)

我正在编写一个Greasemonkey用户脚本,并希望在页面完全完成加载时执行特定代码,因为它返回一个我希望显示的div计数。
问题是,在加载所有内容之前,这个特定的页面有时会占用一些时间。
我试过了,文档$(function() { });$(window).load(function(){ }); Package 器,但是似乎没有一个适合我,尽管我可能应用错了。
我能做的最好的事情就是使用setTimeout(function() { }, 600);,尽管它并不总是可靠的。
在Greasemonkey中使用什么最好的技术来确保特定的代码在页面加载完成时执行?

cotxawn7

cotxawn71#

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

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

在用户脚本中

3vpjnl9f

3vpjnl9f2#

这是一个常见的问题,正如您所说,等待页面加载是不够的--因为 AJAX 可以而且确实在页面加载很久之后才进行更改。
对于这些情况,有一个标准的(比较)健壮的实用程序,它是the waitForKeyElements() utility
像这样使用它:

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

    If in Tampermonkey, use "// @unwrap" to enable sandbox instead.
*/

waitForKeyElements ("YOUR_jQUERY_SELECTOR", actionFunction);

function actionFunction (jNode) {
    //-- DO WHAT YOU WANT TO THE TARGETED ELEMENTS HERE.
    jNode.css ("background", "yellow"); // example
}

给予一个更具体的例子,你的目标页面的确切细节.

krugob8w

krugob8w3#

从Greasemonkey 3.6(2015年11月20日)起,元数据键@run-at支持新值document-idle,只需将其放入Greasemonkey脚本的元数据块即可:

// @run-at      document-idle

文档对此进行了如下描述:
脚本将在页面和所有资源(图像、样式表等)加载完毕并且页面脚本运行之后运行。

szqfcxe2

szqfcxe24#

Brock's answer很好,但我想提供另一种更现代、更优雅的 AJAX 问题解决方案。
因为他的脚本和其他大多数脚本一样,也使用setInterval()来定期检查(300ms),所以它不能立即响应,而且总是有延迟。其他解决方案使用onload事件,在动态页面上,这些事件通常比你想要的触发得早。
可以使用MutationObserver()监听DOM更改,并在创建元素后立即响应这些更改

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

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

尽管check()在每次DOM更改时都会触发,但如果DOM更改非常频繁或您的条件需要很长时间来评估,那么这可能会很慢,因此不要观察document,而是尝试通过观察尽可能小的DOM子树来限制范围。
这种方法非常通用,可以应用于很多情况,如果要多次响应,只要在触发时不断开观察者即可。
另一个用例是,如果您不寻找任何特定的元素,而只是等待页面停止更改,您可以将此与倒计时相结合,每当页面上发生更改时,该倒计时就会重置。

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

// reset timer every time something changes
function resetTimer(changes, observer) {
    clearTimeout(timer);
    timer = setTimeout(action, 3000, observer);
}

function action(observer) {
    observer.disconnect();
    // code
}

这个方法非常通用,你可以监听属性和文本的变化,只需要在选项中将attributescharacterData设置为true

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

xdnvmnnf5#

将脚本 Package 在$(window).load(function(){ })中对我来说从来没有失败过。
也许你的页面已经完成,但仍有一些 AJAX 内容正在加载.
如果是这样的话,Brock Adams中的这段代码可以帮助您:
https://gist.github.com/raw/2625891/waitForKeyElements.js
我通常使用它来监视出现在 postback 上的元素。
像这样使用它:waitForKeyElements("elementtowaitfor", functiontocall)

6ie5vjzr

6ie5vjzr6#

如果您想操作节点,如获取节点值或更改样式,您可以使用此函数等待这些节点

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

然后使用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
})

或使用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的示例

jogvjijk

jogvjijk7#

为了检测XHR是否完成了在网页中的加载,然后它会触发一些函数。我从How do I use JavaScript to store "XHR finished loading" messages in the console in Chrome?得到这个,它真实的有效。

//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(),它很不错。
有Greasemonkey的使用示例。在同一页上运行Greasemonkey脚本,多次?

相关问题