it-swarm.com.de

Wie kann man warten, bis ein Element existiert?

Ich arbeite an einer Erweiterung in Chrome und frage mich: Wie kann ich am besten herausfinden, wann ein Element entsteht? Verwenden Sie einfaches Javascript mit einem Intervall, in dem überprüft wird, bis ein Element vorhanden ist.

185
mattsven

DOMNodeInserted wird zusammen mit den anderen DOM-Mutationsereignissen wegen Leistungsproblemen nicht mehr empfohlen. Die empfohlene Vorgehensweise ist die Verwendung eines MutationObserver , um das DOM zu überwachen. Es wird jedoch nur in neueren Browsern unterstützt. Daher sollten Sie auf DOMNodeInserted zurückgreifen, wenn MutationObserver nicht verfügbar ist.

var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    if (!mutation.addedNodes) return

    for (var i = 0; i < mutation.addedNodes.length; i++) {
      // do things to your newly added nodes here
      var node = mutation.addedNodes[i]
    }
  })
})

observer.observe(document.body, {
    childList: true
  , subtree: true
  , attributes: false
  , characterData: false
})

// stop watching using:
observer.disconnect()
119
hughsk

Ich hatte das gleiche Problem, also schrieb ich ein Plugin dafür.

$(selector).waitUntilExists(function);

Code:

;(function ($, window) {

var intervals = {};
var removeListener = function(selector) {

    if (intervals[selector]) {

        window.clearInterval(intervals[selector]);
        intervals[selector] = null;
    }
};
var found = 'waitUntilExists.found';

/**
 * @function
 * @property {object} jQuery plugin which runs handler function once specified
 *           element is inserted into the DOM
 * @param {function|string} handler 
 *            A function to execute at the time when the element is inserted or 
 *            string "remove" to remove the listener from the given selector
 * @param {bool} shouldRunHandlerOnce 
 *            Optional: if true, handler is unbound after its first invocation
 * @example jQuery(selector).waitUntilExists(function);
 */

$.fn.waitUntilExists = function(handler, shouldRunHandlerOnce, isChild) {

    var selector = this.selector;
    var $this = $(selector);
    var $elements = $this.not(function() { return $(this).data(found); });

    if (handler === 'remove') {

        // Hijack and remove interval immediately if the code requests
        removeListener(selector);
    }
    else {

        // Run the handler on all found elements and mark as found
        $elements.each(handler).data(found, true);

        if (shouldRunHandlerOnce && $this.length) {

            // Element was found, implying the handler already ran for all 
            // matched elements
            removeListener(selector);
        }
        else if (!isChild) {

            // If this is a recurring search or if the target has not yet been 
            // found, create an interval to continue searching for the target
            intervals[selector] = window.setInterval(function () {

                $this.waitUntilExists(handler, shouldRunHandlerOnce, true);
            }, 500);
        }
    }

    return $this;
};

}(jQuery, window));
110
Ryan Lester

Hier ist eine JavaScript-Kernfunktion, die auf die Anzeige eines Elements wartet.

Parameter: 

  1. selector: Diese Funktion sucht nach dem Element $ {Selector}
  2. time: Diese Funktion prüft, ob dieses Element alle $ {time} Millisekunden vorhanden ist.

    function waitForElementToDisplay(selector, time) {
            if(document.querySelector(selector)!=null) {
                alert("The element is displayed, you can put your code instead of this alert.")
                return;
            }
            else {
                setTimeout(function() {
                    waitForElementToDisplay(selector, time);
                }, time);
            }
        }
    

Als Beispiel wird bei der Einstellung von selector="#div1" und time=5000 nach dem HTML-Tag gesucht, dessen id="div1" alle 5000 Millisekunden angezeigt wird.

53

Sie können sich DOMNodeInserted- oder DOMSubtreeModified-Ereignisse anhören, die ausgelöst werden, wenn ein neues Element zum DOM hinzugefügt wird. 

Es gibt auch LiveQuery jQuery Plugin, das erkennen würde, wenn ein neues Element erstellt wird:

$("#future_element").livequery(function(){
    //element created
});
24
serg

Du kannst tun

$('#yourelement').ready(function() {

});

Beachten Sie, dass dies nur funktioniert, wenn das Element im DOM vorhanden ist, wenn es vom Server angefordert wird. Wenn das Element dynamisch über JavaScript hinzugefügt wird, funktioniert es nicht und Sie müssen möglicherweise die anderen Antworten prüfen.

20
Splynx

Ich habe diesen Ansatz verwendet, um auf das Erscheinen eines Elements zu warten, damit ich danach die anderen Funktionen ausführen kann.

Angenommen, die Funktion doTheRestOfTheStuff(parameters) sollte nur aufgerufen werden, nachdem das Element mit der ID the_Element_ID angezeigt wurde oder das Laden abgeschlossen ist.

var existCondition = setInterval(function() {
 if ($('#the_Element_ID').length) {
    console.log("Exists!");
    clearInterval(existCondition);
    doTheRestOfTheStuff(parameters);
 }
}, 100); // check every 100ms
14
prime

Für einen einfachen Ansatz mit jQuery habe ich festgestellt, dass dies gut funktioniert:

  // Wait for element to exist.
  function elementLoaded(el, cb) {
    if ($(el).length) {
      // Element is now loaded.
      cb($(el));
    } else {
      // Repeat every 500ms.
      setTimeout(function() {
        elementLoaded(el, cb)
      }, 500);
    }
  };

  elementLoaded('.element-selector', function(el) {
    // Element is ready to use.
    el.click(function() {
      alert("You just clicked a dynamically inserted element");
    });
  });

Hier wird einfach alle 500ms geprüft, ob das Element geladen ist. Wenn es dann ist, können wir es verwenden.

Dies ist besonders nützlich, um Klick-Handler zu Elementen hinzuzufügen, die dem Dokument dynamisch hinzugefügt wurden.

8
Hedley Smith

Wie wäre es mit der insertQuery library? 

insertQuery verwendet CSS-Animations-Callbacks, die an die angegebenen Selektoren angefügt sind, um einen Callback auszuführen, wenn ein Element erstellt wird. Mit dieser Methode können Callbacks ausgeführt werden, wenn ein Element erstellt wird, nicht nur beim ersten Mal.

Von github:

Nicht-dom-Ereignismethode zum Auffinden von Knoten. Und es verwendet Selektoren.

Es ist nicht nur für eine breitere Browserunterstützung gedacht, es kann für bestimmte Dinge besser sein als DOMMutationObserver.

Warum?

  • Weil DOM-Ereignisse den Browser verlangsamen, und insertQuery nicht
  • Weil DOM Mutation Observer weniger Browserunterstützung bietet als Einfügungsabfrage
  • Denn mit insertQuery können Sie DOM-Änderungen mithilfe von Selektoren ohne Performance-Overhead filtern!

Weit verbreitete Unterstützung!

IE10 + und meistens alles andere (einschließlich Handy)

8
b3wii

Hier ist eine Funktion, die als dünner Wrapper für MutationObserver dient. Die einzige Voraussetzung ist, dass der Browser MutationObserver unterstützt. Es gibt keine Abhängigkeit von JQuery. Führen Sie den folgenden Ausschnitt aus, um ein Funktionsbeispiel zu sehen.

function waitForMutation(parentNode, isMatchFunc, handlerFunc, observeSubtree, disconnectAfterMatch) {
  var defaultIfUndefined = function(val, defaultVal) {
    return (typeof val === "undefined") ? defaultVal : val;
  };

  observeSubtree = defaultIfUndefined(observeSubtree, false);
  disconnectAfterMatch = defaultIfUndefined(disconnectAfterMatch, false);

  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      if (mutation.addedNodes) {
        for (var i = 0; i < mutation.addedNodes.length; i++) {
          var node = mutation.addedNodes[i];
          if (isMatchFunc(node)) {
            handlerFunc(node);
            if (disconnectAfterMatch) observer.disconnect();
          };
        }
      }
    });
  });

  observer.observe(parentNode, {
    childList: true,
    attributes: false,
    characterData: false,
    subtree: observeSubtree
  });
}

// Example
waitForMutation(
  // parentNode: Root node to observe. If the mutation you're looking for
  // might not occur directly below parentNode, pass 'true' to the
  // observeSubtree parameter.
  document.getElementById("outerContent"),
  // isMatchFunc: Function to identify a match. If it returns true,
  // handlerFunc will run.
  // MutationObserver only fires once per mutation, not once for every node
  // inside the mutation. If the element we're looking for is a child of
  // the newly-added element, we need to use something like
  // node.querySelector() to find it.
  function(node) {
    return node.querySelector(".foo") !== null;
  },
  // handlerFunc: Handler.
  function(node) {
    var elem = document.createElement("div");
    elem.appendChild(document.createTextNode("Added node (" + node.innerText + ")"));
    document.getElementById("log").appendChild(elem);
  },
  // observeSubtree
  true,
  // disconnectAfterMatch: If this is true the hanlerFunc will only run on
  // the first time that isMatchFunc returns true. If it's false, the handler
  // will continue to fire on matches.
  false);

// Set up UI. Using JQuery here for convenience.

$outerContent = $("#outerContent");
$innerContent = $("#innerContent");

$("#addOuter").on("click", function() {
  var newNode = $("<div><span class='foo'>Outer</span></div>");
  $outerContent.append(newNode);
});
$("#addInner").on("click", function() {
  var newNode = $("<div><span class='foo'>Inner</span></div>");
  $innerContent.append(newNode);
});
.content {
  padding: 1em;
  border: solid 1px black;
  overflow-y: auto;
}
#innerContent {
  height: 100px;
}
#outerContent {
  height: 200px;
}
#log {
  font-family: Courier;
  font-size: 10pt;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Create some mutations</h2>
<div id="main">
  <button id="addOuter">Add outer node</button>
  <button id="addInner">Add inner node</button>
  <div class="content" id="outerContent">
    <div class="content" id="innerContent"></div>
  </div>
</div>
<h2>Log</h2>
<div id="log"></div>

5
Ivan Karajas

Hier ist eine reine Javascript-Funktion, mit der Sie auf alles warten können. Legen Sie das Intervall länger fest, um weniger CPU-Ressourcen zu benötigen.

/**
 * @brief Wait for something to be ready before triggering a timeout
 * @param {callback} isready Function which returns true when the thing we're waiting for has happened
 * @param {callback} success Function to call when the thing is ready
 * @param {callback} error Function to call if we time out before the event becomes ready
 * @param {int} count Number of times to retry the timeout (default 300 or 6s)
 * @param {int} interval Number of milliseconds to wait between attempts (default 20ms)
 */
function waitUntil(isready, success, error, count, interval){
    if (count === undefined) {
        count = 300;
    }
    if (interval === undefined) {
        interval = 20;
    }
    if (isready()) {
        success();
        return;
    }
    // The call back isn't ready. We need to wait for it
    setTimeout(function(){
        if (!count) {
            // We have run out of retries
            if (error !== undefined) {
                error();
            }
        } else {
            // Try again
            waitUntil(isready, success, error, count -1, interval);
        }
    }, interval);
}

Um dies beispielsweise in jQuery aufzurufen, verwenden Sie Folgendes:

waitUntil(function(){
    return $('#myelement').length > 0;
}, function(){
    alert("myelement now exists");
}, function(){
    alert("I'm bored. I give up.");
});
3
xgretsch

Hier ist eine vielversprechende Lösung in Vanilla Javascript (keine unordentlichen Rückrufe). Standardmäßig wird alle 200 ms geprüft.

function waitFor(selector) {
    return new Promise(function (res, rej) {
        waitForElementToDisplay(selector, 200);
        function waitForElementToDisplay(selector, time) {
            if (document.querySelector(selector) != null) {
                res(document.querySelector(selector));
            }
            else {
                setTimeout(function () {
                    waitForElementToDisplay(selector, time);
                }, time);
            }
        }
    });
}
2
blaster

Ein saubereres Beispiel mit MutationObserver:

new MutationObserver( mutation => {
    if (!mutation.addedNodes) return
    mutation.addedNodes.forEach( node => {
        // do stuff with node
    })
})
2
Zaz

Fügen Sie einfach den gewünschten Selektor hinzu. Sobald das Element gefunden wurde, können Sie in der Rückruffunktion darauf zugreifen.

const waitUntilElementExists = (selector, callback) => {
const el = document.querySelector(selector);

if (el){
    return callback(el);
}

setTimeout(() => waitUntilElementExists(selector, callback), 500);
}

waitUntilElementExists('.wait-for-me', (el) => console.log(el));
0
PossessWithin

Wenn Sie möchten, dass die Suche nach einer Weile unterbrochen wird (Timeout), funktioniert die folgende jQuery. Es wird nach 10 Sekunden eine Zeitüberschreitung auftreten. Ich musste diesen Code anstelle von reinem JS verwenden, da ich eine Eingabe über den Namen auswählen musste und Probleme hatte, einige der anderen Lösungen zu implementieren.

 // Wait for element to exist.

    function imageLoaded(el, cb,time) {

        if ($(el).length) {
            // Element is now loaded.

            cb($(el));

            var imageInput =  $('input[name=product\\[image_location\\]]');
            console.log(imageInput);

        } else if(time < 10000) {
            // Repeat every 500ms.
            setTimeout(function() {
               time = time+500;

                imageLoaded(el, cb, time)
            }, 500);
        }
    };

    var time = 500;

    imageLoaded('input[name=product\\[image_location\\]]', function(el) {

     //do stuff here 

     },time);
0
S-Thomas

Eine Lösung, die eine Promise zurückgibt und die Verwendung eines Timeouts zulässt (kompatible IE 11+):

"use strict";

function waitUntilElementLoaded(selector) {
    var timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;

    var start = performance.now();
    var now = 0;

    return new Promise(function (resolve, reject) {
        var interval = setInterval(function () {
            var element = document.querySelector(selector);

            if (element instanceof HTMLElement) {
                clearInterval(interval);

                resolve();
            }

            now = performance.now();

            if (now - start >= timeout) {
                reject("Could not find the element " + selector + " within " + timeout + " ms");
            }
        }, 100);
    });
}

"use strict";

function waitUntilElementsLoaded(selector) {
    var timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;

    var start = performance.now();
    var now = 0;

    return new Promise(function (resolve, reject) {
        var interval = setInterval(function () {
            var elements = document.querySelectorAll(selector);

            if (elements instanceof NodeList) {
                clearInterval(interval);

                resolve(elements);
            }

            now = performance.now();

            if (now - start >= timeout) {
                reject("Could not find elements " + selector + " within " + timeout + " ms");
            }
        }, 100);
    });
}

Beispiele:

waitUntilElementLoaded('#message', 800).then(function(element) {
    // element found and available

    element.innerHTML = '...';
}).catch(function() {
    // element not found within 800 milliseconds
});

waitUntilElementsLoaded('.message', 10000).then(function(elements) {
    for(const element of elements) {
        // ....
    }
}).catch(function(error) {
    // elements not found withing 10 seconds
});

Funktioniert sowohl für eine Liste von Elementen als auch für ein einzelnes Element.

0
Anwar