Wie kann überprüft werden, ob ein Element auf einer Seite geladen wurde, bevor ein Skript ausgeführt wird?

Lesezeit: 7 Minuten

Benutzeravatar von user2052567
Benutzer2052567

Also erstelle ich meine Seite in meiner Unternehmensvorlage, die uns nur den Zugriff auf den Hauptteil der Seite ermöglicht. Wir haben keinen Zugriff auf das Head-Tag und im unteren Teil der Seite sind Skripts geladen, auf die wir keinen Zugriff haben. Eines dieser Skripte lädt dynamisch ein Element auf die Seite. Ich muss ein anderes Skript für dieses Element ausführen, aber da das Element erst auf der Seite geladen wird, nachdem mein Skript bereits ausgeführt wurde, kann ich nicht auf dieses Element zugreifen. Gibt es eine Möglichkeit, zu überprüfen, ob dieses Element bereits auf der Seite geladen wurde, bevor ich mein Skript ausführe?

Lassen Sie mich wissen, wenn ich es besser erklären muss.

<head>Don't have access</head>


<body>
   <!--Needs to manipulate the element created by the companyScript.js--> 
   <script src="https://stackoverflow.com/questions/34863788/myScript.js"></script>

   <!--Script that runs after mine, which I don't have access too-->
   <script src="companyScript.js">
       /*Dynamically adds <div class="element"></div> to page*/
   </script>
</body>

  • Schreiben Sie ein Skript, um Ihr Skript am Ende der Seite anzuhängen, damit es danach geladen wird

    – Johnny 5

    18. Januar 2016 um 20:49 Uhr


  • If ( $('.element').length )

    – adeneo

    18. Januar 2016 um 20:53 Uhr

  • Verwenden Sie den Code, der das Element hinzufügt, um Ihren Code auszuführen, der sich auf dieses Element auswirken würde. Benötigen Sie ein besseres Verständnis des Problems, um qualitativ hochwertigere Antworten zu erhalten und weniger zu raten

    – charlietfl

    18. Januar 2016 um 20:56 Uhr


  • @ johnny5, das sich nicht damit befasst, ob ein dynamisch hinzugefügtes Element vorhanden ist oder nicht

    – charlietfl

    18. Januar 2016 um 21:00 Uhr


Ich habe einmal mit einem Bären gerungen. Benutzeravatar
I habe einmal mit einem Bär gekämpft.

Version 2022, mit MutationObserver

Den 2020-Code umgeschrieben, um a zu verwenden MutationObserver statt Umfragen.

/**
 * Wait for an element before resolving a promise
 * @param {String} querySelector - Selector of element to wait for
 * @param {Integer} timeout - Milliseconds to wait before timing out, or 0 for no timeout              
 */
function waitForElement(querySelector, timeout){
  return new Promise((resolve, reject)=>{
    var timer = false;
    if(document.querySelectorAll(querySelector).length) return resolve();
    const observer = new MutationObserver(()=>{
      if(document.querySelectorAll(querySelector).length){
        observer.disconnect();
        if(timer !== false) clearTimeout(timer);
        return resolve();
      }
    });
    observer.observe(document.body, {
      childList: true, 
      subtree: true
    });
    if(timeout) timer = setTimeout(()=>{
      observer.disconnect();
      reject();
    }, timeout);
  });
}

waitForElement("#idOfElementToWaitFor", 3000).then(function(){
    alert("element is loaded.. do stuff");
}).catch(()=>{
    alert("element did not load in 3 seconds");
});

Version 2020, mit Versprechungen

Dieser Code fragt das DOM 10x/Sekunde ab und löst ein Promise auf, wenn es vor dem optionalen Timeout gefunden wird.

/**
 * Wait for an element before resolving a promise
 * @param {String} querySelector - Selector of element to wait for
 * @param {Integer} timeout - Milliseconds to wait before timing out, or 0 for no timeout              
 */
function waitForElement(querySelector, timeout=0){
    const startTime = new Date().getTime();
    return new Promise((resolve, reject)=>{
        const timer = setInterval(()=>{
            const now = new Date().getTime();
            if(document.querySelector(querySelector)){
                clearInterval(timer);
                resolve();
            }else if(timeout && now - startTime >= timeout){
                clearInterval(timer);
                reject();
            }
        }, 100);
    });
}


waitForElement("#idOfElementToWaitFor", 3000).then(function(){
    alert("element is loaded.. do stuff");
}).catch(()=>{
    alert("element did not load in 3 seconds");
});

Ursprüngliche Antwort

function waitForElement(id, callback){
    var poops = setInterval(function(){
        if(document.getElementById(id)){
            clearInterval(poops);
            callback();
        }
    }, 100);
}

waitForElement("idOfElementToWaitFor", function(){
    alert("element is loaded.. do stuff");
});

  • Genial! 😉 SO einfach… und doch effektiv! Der einzige Code, der effektiv auf Angular funktioniert, ist der Aufruf der Funktion on ngAfterViewInit() und das ist es! Vielen Dank!

    – Pedro Ferreira

    29. Oktober 2019 um 21:49 Uhr


  • Ich mochte Ihren 2020-Code, könnten Sie bitte die if-Anweisungen in der Funktion waitForElement erläutern?

    – Mathew

    23. August 2020 um 12:42 Uhr

  • Das ist ein sehr guter Code, der etwas erklärt werden muss, aber was dieser Code tut, ist zu erkennen, ob das Element geladen ist, und dann Dinge zu tun, was dieser Code nicht tut, ist, Dinge zu tun, WÄHREND das Element geladen wird

    – Mathew

    23. August 2020 um 12:44 Uhr

  • @Mathew – Das machen Versprechen, sie lassen dich Dinge tun, während du auf etwas anderes wartest. Das if -Anweisung prüft nur, ob das Element bereits existiert.

    – I habe einmal mit einem Bär gekämpft.

    24. August 2020 um 14:41 Uhr

  • @I habe einmal mit einem Bär gekämpft. Ich versuche zu deaktivieren observer.disconnect() in MutationObserver, um es immer am Laufen zu halten, aber ich finde es nicht heraus, dies zu tun. Irgendeine Ahnung?

    – LuizC

    28. September um 22:44 Uhr


Hatchets Benutzeravatar
Beil

Klingt nach einem Job für MutationObserver!

EIN MutationObserver ist wie ein Ereignis-Listener: Sie können ihn an jedes DOM-Element anhängen, um auf Änderungen zu warten:

var observer = new MutationObserver(function (mutationRecords) {
    console.log("change detected");
});

Dem Callback wird ein Array von übergeben MutationRecords, die verschiedene Listen von hinzugefügten/gelöschten/geänderten Knoten enthalten.

Dann hängen wir den Beobachter an einen beliebigen Knoten an:

observer.observe(document.body, {childList: true});
// second argument is a config: in this case, only fire the callback when nodes are added or removed

Notiz: IE-Unterstützung ist nicht erstaunlich. (Überraschung, Überraschung) Funktioniert nur auf IE 11. (Edge unterstützt es jedoch.)

Hier ist eine weitere SO-Frage zum Erkennen von Änderungen am DOM: Änderungen im DOM erkennen

Ausschnitt:

document.querySelector("button").addEventListener("click", function () {
  document.body.appendChild(document.createElement("span"));
});

var observer = new MutationObserver(function (m) {
  if (m[0].addedNodes[0].nodeName === "SPAN")
    document.querySelector("div").innerHTML += "Change Detected<br>";
});

observer.observe(document.body, {childList: true});
<button>Click</button>
<div></div>

Ich würde davon abraten, MutationObserver zu verwenden. Dieser Ansatz hat viele Nachteile: Er verlangsamt das Laden von Seiten und hat eine schlechte Browserunterstützung. Es gibt Situationen, in denen dies der einzige Ansatz ist, um das vorliegende Problem zu lösen.

Ein besserer Ansatz ist die Verwendung von onload DOM-Ereignis. Dieses Ereignis funktioniert mit Tags wie iframe und img. Für andere Tags ist dies der Pseudocode, von dem Sie sich inspirieren lassen können:

<body>
<script>
function divLoaded(event){
  alert(event.target.previousSibling.previousSibling.id);
}
</script>
<div id="element_to_watch">This is an example div to watch it's loading</div>
<iframe style="display: none; width: 0; height: 0" onload="divLoaded(event)"/>
</body>

HINWEIS: Der Trick besteht darin, nach jedem Element, das Sie auf das Laden überwachen möchten, ein iframe- oder img-Element anzuhängen.

  • Wenn Sie diesem Ansatz folgen, kann diese spezielle Frage auf viele Arten gelöst werden, z. B. können Sie das Laden des Skript-Tags beobachten und dann mithilfe von Javascript dynamisch ein anderes Skript laden.

    – Shyam Swaroop

    27. Februar 2020 um 19:49 Uhr

Hier ist eine in ClojureScript geschriebene Funktion, die eine Funktion aufruft, wenn eine Bedingung erfüllt ist.

(require '[cljs.core.async :as a :refer [<!]]
         '[cljs-await.core :refer [await]])
(require-macros '[cljs.core.async.macros :refer [go]])

(defn wait-for-condition
  [pred-fn resolve-fn & {:keys [reject-fn timeout frequency]
                         :or {timeout 30 frequency 100}}]

  (let [timeout-ms (atom (* timeout 1000))]
    ;; `def` instead of `let` so it can recurse
    (def check-pred-satisfied
      (fn []
        (swap! timeout-ms #(- % frequency))
        (if (pred-fn)
          (resolve-fn)
          (if (pos? @timeout-ms)
            (js/setTimeout check-pred-satisfied frequency)
            (when reject-fn
              (reject-fn))))))

    (go (<! (await (js/Promise. #(js/setTimeout check-pred-satisfied frequency)))))))

Dann könntest du sowas machen

wait_for_condition((id) => document.getElementById(id), () => alert("it happened"))

oder

(wait-for-condition #(js/document.getElementById id)
                    #(js/alert "it happened")
                    :frequency 250
                    :timeout 10)

Benutzeravatar von Abhinandan Mittal
Abhinandan Mittal

Erweiterung der Lösung von @i-wrestled-a-bear-once. Mit diesem js-Code können wir das Popup auch deaktivieren, wenn die Zielkomponente nicht mehr im DOM vorhanden ist.

Es kann für Fälle verwendet werden, in denen Sie nach einer Dateieingabe für eine Anfrage fragen und die Datei nicht anzeigen möchten, nachdem er mit der Anfrage fertig ist.

// Call this to run a method when a element removed from DOM
function waitForElementToUnLoad(querySelector) {
    const startTime = new Date().getTime();
    return new Promise((resolve, reject)=>{
        const timer = setInterval(()=>{
            const now = new Date().getTime();
            if(!document.querySelector(querySelector)) {
                clearInterval(timer);
                resolve();
            }
        }, 1000);
    });
}

// Call this to run a method when a element added to DOM, set timeout if required.
// Checks every second.
function waitForElementToLoad(querySelector, timeout=0) {
    const startTime = new Date().getTime();
    return new Promise((resolve, reject)=>{
        const timer = setInterval(()=>{
            const now = new Date().getTime();
            if(document.querySelector(querySelector)){
                clearInterval(timer);
                resolve();
            }else if(timeout && now - startTime >= timeout){
                clearInterval(timer);
                reject();
            }
        }, 1000);
    });
}

// Removing onclose popup if no file is uploaded.
function executeUnloadPromise(id) {
  waitForElementToUnLoad(id).then(function(){
      window.onbeforeunload = null;
      executeLoadPromise("#uploaded-file");
  });
}

// Adding onclose popup if a file is uploaded.
function executeLoadPromise(id) {
  waitForElementToLoad(id).then(function(){
      window.onbeforeunload = function(event) { 
        return "Are you sure you want to leave?"; 
      }
      executeUnloadPromise("#uploaded-file");
  });
}

executeLoadPromise("#uploaded-file");

Würde mich über Vorschläge freuen, wie ich das besser machen kann.

1431230cookie-checkWie kann überprüft werden, ob ein Element auf einer Seite geladen wurde, bevor ein Skript ausgeführt wird?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy