0

DOM要素が完全にロードされたときにのみJavaScript関数を一度だけ実行するのに少し苦労しています。setIntervals、seTimeouts、FORループ、IFステートメント、ループなどの無数の組み合わせを試しましたが、WHILEどこにも行きませんでした。

私はそれを一度動作させることができましたが、関数を2秒遅らせることによってしか動作させることができなかったので、それはヒットアンドミスです(ロードにかかる時間を正確に知ることができないため、これは良くありません)そして同じ機能を何度も何度もすばやく再発射しますが、これも良くありません。

常にページをスキャンして、要素が存在し、コンテンツ(innerHTML != undefined、または何か)があるかどうかを確認し、コードのブロックが読み込まれるとすぐに(1回だけ)実行してから、ページのスキャンを停止するものが必要です。

誰かがこれを行う方法を見つけましたか?また、jQueryではなくJavaScriptが必要です。

ありがとう。

元のコード

function injectLink_Bridge(){
    setTimeout(function(){
        injectLink();
    }, 2000);
}

function injectLink(){
    var headerElement = document.getElementsByClassName("flex-module-header");

    if (headerElement.innerHTML == undefined) {
        console.log("Element doesn't exist. Restarting function");

        setTimeout(function(){
            injectLink_Bridge(); //I can't remember if the bridge is necessary or not
        }, 2000); 
    } else {
        console.log("Element exists. Injecting");

        setTimeout(function(){
            headerElement[1].innerHTML += "code" //Inject code into the second instance of the class-array
        }, 2000);
    }
}

完成したコード

function injectLink(){
    var headerElement = document.getElementsByClassName("flex-module-header")[1]; //Get the second instance

    if(headerElement && headerElement.innerHTML != ""){
        console.log("Element exists and has content. Injecting code...");
        headerElement.innerHTML += "code"; //Currently revising, due to T.J. Crowder's side-note
    } else {
        console.log("Element doesn't exist or has no content. Refiring function...");
        setTimeout(injectLink, 250);
    }
}
4

2 に答える 2

3

コードを投稿した後、回答を更新しました:

getElementsByClassNameNodeList要素ではなく を返します。プロパティNodeListを持っていません。innerHTML2 番目に一致する要素が必要な場合は、 を使用[1]してそれを取得し、何かが返されたかどうかをテストします (または、必要に応じて を使用.length > 1して最初に確認できますが、存在しないインデックスに対してNodeList返されると文書化されています)。nullまた、既存の関数を に渡すときに関数ラッパーは必要ありませんsetTimeout。そう:

function injectLink(){
    var headerElement = document.getElementsByClassName("flex-module-header")[1];

    if (!headerElement) {
        console.log("Element doesn't exist. Restarting function");

        setTimeout(injectLink, 2000); 
    } else {
        console.log("Element exists. Injecting");

        // Do you really want a further two second delay?
        setTimeout(function(){
            headerElement.innerHTML += "code"; //Inject code into the second instance of the class-array
        }, 2000);
    }
}

補足: を使用する.innerHTML += "markup";ことは、通常、要素にコンテンツを追加する優れた方法ではありません。これを行うと、ブラウザは次のように動作します。

  1. 要素とその子孫要素をスピンして、JavaScript レイヤーに提供する HTML 文字列を作成します。
  2. 要素からすべてのコンテンツを破棄します。これには、子孫要素のイベント ハンドラーが削除されるという副産物があります。
  3. HTML 文字列を解析し、新しいノードと要素を構築します。

そのため、少し作業が必要であり、イベント ハンドラーを一掃する可能性もあります。新しい子要素を追加する場合は、 と の使用を見てcreateElementくださいappendChild。さらにテキスト コンテンツを追加する場合は、 と を参照しcreateTextNodeappendChildください。


元の答え:

要素に を指定するとid(ただし、要素を見つける方法に関係なく同じ概念が機能します)、次のことができます。

(function() {
    setTimeout(check, 0);
    function check() {
        var elm = document.getElementById('theId');
        if (!elm) {
            setTimeout(check, 250); // Check again in a quarter second or so
            return;
        }

        // Use the element
    }
})();

そこで、最初のチェックをほぼ即座に開始し、要素が見つからない場合は、250 ミリ秒後に再度チェックをスケジュールします。前のチェックで要素が見つからなかった場合にのみ次のチェックをスケジュールするため、要素を見つけるために必要な回数だけループします。

要素に が含まれていない場合はid、おそらく何らかの方法で( querySelectorquerySelectorAllなど) を見つけているため、見つかったかどうかがわかり、次のチェックをスケジュールできます。

おそらく制限をかける価値があります。たとえば、次のようになります。

(function() {
    var start = new Date();
    setTimeout(check, 0);
    function check() {
        var elm = document.getElementById('theId');
        if (!elm) {
            if (new Date() - start > 5000) { // More than five seconds
                throw "Couldn't find the element";
            }
            setTimeout(check, 250); // Check again in a quarter second or so
            return;
        }

        // Use the element
    }
})();

...そのため、HTML を変更して要素が存在しなくなった場合、テスト時にエラーが表示され、コードを更新するように促されます。

于 2012-04-30T08:38:49.077 に答える
1

編集:コードを表示したので、いくつかの問題があります。

たとえばgetElementsByClassName()、配列を返すため、これを行うことはできません。

var headerElement = document.getElementsByClassName("flex-module-header");
if (headerElement.innerHTML == undefined) 

これを行う必要があります:

var headerElement = document.getElementsByClassName("flex-module-header");
if (!headerElement || headerElement.length == 0 || headerElement[0].innerHTML == undefined) 

質問でコードが提供される前の元の回答:

問題全体を示していただければ、おそらくもっと洗練されたものを思いつくことができますが、あなたの話に基づいて、今提案できるのは鈍力法だけです。

(function() {
    var item, cnt = 0; 
    var pollTimer = setInterval(function() {
        ++cnt;
        if (!item) {
            // cache the item if found so future checks will be faster
            item = document.getElementById("testObject");
        }
        if (item && item.innerHTML != "") {
            // the item has innerHTML now, you can process it
            // with code here
            clearInterval(pollTimer);
        } else {
            if (cnt > 100) {
               // if not found after 100 checks (20 seconds)
               // then stop looking so we don't keep going forever
               clearInterval(pollTimer);
            }
        }
    }, 200);
}){};
于 2012-04-30T08:42:27.187 に答える