web-dev-qa-db-ja.com

コードを実行する前にページがロードされるのを待つユーザースクリプト?

Greasemonkeyユーザースクリプトを記述しています。表示するdivカウントを返すため、ページの読み込みが完全に終了したときに特定のコードを実行します。

問題は、この特定のページがすべてがロードされる前に少し時間がかかることです。

$(function() { });および$(window).load(function(){ });ラッパーをドキュメント化してみました。しかし、私はそれらを間違って適用しているかもしれませんが、私にとってはうまくいかないようです。

最善の方法は、setTimeout(function() { }, 600);を使用することです。ただし、これは常に信頼できるとは限りませんが。

ページの読み込みが完了したときに特定のコードが実行されるようにするために、Greasemonkeyで使用する最適な手法は何ですか?

59
Myne Mai

Greasemonkey(通常)にはjQueryがありません。したがって、一般的なアプローチは

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

あなたのユーザースクリプト内

55
devnull69

これはよくある問題であり、あなたが言ったように、ページのロードを待つだけでは十分ではありません-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
}

より具体的な例については、ターゲットページの正確な詳細を入力してください。

46
Brock Adams

Greasemonkey 3.6(2015年11月20日)のメタデータキー@run-atは新しい値をサポートしますdocument-idle。これをGreasemonkeyスクリプトのメタデータブロックに配置するだけです。

// @run-at      document-idle

documentation は、次のように説明しています。

スクリプトは、ページとすべてのリソース(画像、スタイルシートなど)が読み込まれ、ページスクリプトが実行された後に実行されます。

23
Leviathan

スクリプトを$(window).load(function(){ })でラップすることは決して失敗しませんでした。

ページが終了した可能性がありますが、まだロードされているajaxコンテンツがあります。

その場合、 Brock Adams からのこの素敵なコードはあなたを助けることができます:
https://Gist.github.com/raw/2625891/waitForKeyElements.js

私は通常、postbackに現れる要素を監視するために使用します。

次のように使用します:waitForKeyElements("elementtowaitfor", functiontocall)

10
RASG

ノードの値の取得やスタイルの変更などのノードを操作する場合は、この関数を使用してこれらのノードを待つことができます

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

3
bilabila

ブロックの答え は良いですが、完全性のためにAJAX問題の別の解決策を提供したいと思います。彼のスクリプトはsetInterval()定期的に(300ミリ秒)チェックするには、すぐに応答できません。

すぐに応答する必要がある場合は、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が頻繁に変更されるか、条件の評価に時間がかかる場合、これは遅くなる可能性があります。

別のユースケースは、特定の要素を探しているのではなく、ページの変更が停止するのを待っている場合です。これをsetTimeout()と組み合わせて、それも待つことができます。

_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
}
_

この方法は非常に用途が広いので、属性とテキストの変更もリッスンできます。オプションでattributescharacterDatatrueに設定するだけです

_observer.observe(document, {childList: true, attributes: true, characterData: true, subtree: true});
_
2
goweon

XHRがWebページへのロードを完了したかどうかを検出するために、何らかの機能をトリガーします。これは ChromeのコンソールにJavaScriptを使用して「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をフィルター処理する方法がわかりません。

もう1つのメソッドは、niceであるwaitForKeyElements()です。 https://Gist.github.com/BrockA/2625891
Greasemonkey用のサンプルがあります。 同じページでGreasemonkeyスクリプトを複数回実行しますか?

1
Dave B