it-swarm.com.de

Ereignis, wenn das Element zur Seite hinzugefügt wurde

Dies wurde zuvor hier diskutiert: Wie führt man eine Aktion durch, wenn ein Element mit Jquery zu einer Seite hinzugefügt wird?

Der Antwortende schlug vor, ein benutzerdefiniertes Ereignis auszulösen, wenn der Seite ein Div hinzugefügt wurde. Ich schreibe jedoch eine Chrome-Erweiterung und habe keinen Zugriff auf die Seitenquelle. Was sind meine Optionen hier? Theoretisch könnte ich einfach setTimeout verwenden, um kontinuierlich nach der Präsenz des Elements zu suchen und meine Aktion hinzuzufügen, wenn das Element vorhanden ist.

115
Kevin Burke

Da DOM-Mutationsereignisse jetzt veraltet (siehe Hinweis unten) mit den neuesten Spezifikationen sind und Sie keine Kontrolle über die eingefügten Elemente haben, da sie durch den Code einer anderen Person hinzugefügt werden, besteht die einzige Möglichkeit darin, ständig nach ihnen zu suchen .

function checkDOMChange()
{
    // check for any new element being inserted here,
    // or a particular node being modified

    // call the function again after 100 milliseconds
    setTimeout( checkDOMChange, 100 );
}

Sobald diese Funktion aufgerufen wird, wird sie alle xxx Millisekunden ausgeführt. Ich habe 100 gewählt, also 1/10 (ein Zehntel) einer Sekunde. Wenn Sie keine Echtzeitelemente benötigen, sollte dies ausreichend sein.

Bearbeiten

Wie Ben Davis kommentiert, führt die DOM Level 4-Spezifikation Mutationsbeobachter (auch auf Mozilla docs ) ein, die die abgelehnten Mutationsereignisse ersetzen.

79
Jose Faeti

Die eigentliche Antwort lautet "Mutationsbeobachter verwenden" (wie in dieser Frage beschrieben: Feststellen, ob ein HTML-Element dynamisch zum DOM hinzugefügt wurde ), jedoch ist die Unterstützung (speziell für den IE) begrenzt ( http: // caniuse.com/mutationobserver ).

Die eigentliche ACTUAL-Antwort lautet also: "Verwenden Sie Mutationsbeobachter ... schließlich. Aber gehen Sie jetzt mit Jose Faetis Antwort" :)

26
Asfand Qazi

Sie können auch CSS3-Animationsereignisse ausnutzen, um benachrichtigt zu werden, wenn ein bestimmtes Element zum DOM hinzugefügt wird: http://www.backalleycoder.com/2012/04/25/i-want-a-damnodeinserted/

15
jokeyrhyme

Sie können livequery plugin für jQuery verwenden. Sie können einen Selektorausdruck wie folgt angeben:

$("input[type=button].removeItemButton").livequery(function () {
    $("#statusBar").text('You may now remove items.');
});

Jedes Mal, wenn eine Schaltfläche einer removeItemButton-Klasse hinzugefügt wird, wird eine Meldung in der Statusleiste angezeigt.

In Bezug auf die Effizienz sollten Sie dies vermeiden, aber Sie können das Plugin auf jeden Fall nutzen, anstatt eigene Event-Handler zu erstellen.

Wieder besuchte Antwort

Die obige Antwort war nur dazu gedacht, Erkennen, dass ein Element zum DOM hinzugefügt über das Plugin hinzugefügt wurde.

Am wahrscheinlichsten wäre jedoch ein jQuery.on()-Ansatz, zum Beispiel:

$("#myParentContainer").on('click', '.removeItemButton', function(){
          alert($(this).text() + ' has been removed');
});

Wenn Sie über dynamische Inhalte verfügen, die beispielsweise auf Klicks reagieren sollen, sollten Sie Ereignisse am besten mit jQuery.on an einen übergeordneten Container binden.

13

ETA 24 Apr 17 Ich wollte dies ein bisschen mit etwas async/await Magie vereinfachen, wie es das macht viel prägnanter:

Unter Verwendung des gleichen Versprochen-Beobachtbaren:

const startObservable = (domNode) => {
  var targetNode = domNode;

  var observerConfig = {
    attributes: true,
    childList: true,
    characterData: true
  };

  return new Promise((resolve) => {
      var observer = new MutationObserver(function (mutations) {
         // For the sake of...observation...let's output the mutation to console to see how this all works
         mutations.forEach(function (mutation) {
             console.log(mutation.type);
         });
         resolve(mutations)
     });
     observer.observe(targetNode, observerConfig);
   })
} 

Ihre anrufende Funktion kann so einfach sein wie:

const waitForMutation = async () => {
    const button = document.querySelector('.some-button')
    if (button !== null) button.click()
    try {
      const results = await startObservable(someDomNode)
      return results
    } catch (err) { 
      console.error(err)
    }
}

Wenn Sie eine Zeitüberschreitung hinzufügen möchten, können Sie ein einfaches Promise.race - Muster verwenden, wie hier gezeigt :

const waitForMutation = async (timeout = 5000 /*in ms*/) => {
    const button = document.querySelector('.some-button')
    if (button !== null) button.click()
    try {

      const results = await Promise.race([
          startObservable(someDomNode),
          // this will throw after the timeout, skipping 
          // the return & going to the catch block
          new Promise((resolve, reject) => setTimeout(
             reject, 
             timeout, 
             new Error('timed out waiting for mutation')
          )
       ])
      return results
    } catch (err) { 
      console.error(err)
    }
}

Original

Sie können dies ohne Bibliotheken tun, müssen jedoch einige ES6-Komponenten verwenden. Achten Sie daher auf Kompatibilitätsprobleme (d. H., Wenn Ihre Zielgruppe hauptsächlich Amish-, Luddite- oder, was noch schlimmer ist, IE8-Benutzer sind).

Zuerst verwenden wir die MutationObserver-API , um ein Observer-Objekt zu erstellen. Wir werden dieses Objekt in ein Versprechen hüllen und resolve(), wenn der Rückruf ausgelöst wird (h/t davidwalshblog) david walsh Blogartikel über Mutationen :

const startObservable = (domNode) => {
    var targetNode = domNode;

    var observerConfig = {
        attributes: true,
        childList: true,
        characterData: true
    };

    return new Promise((resolve) => {
        var observer = new MutationObserver(function (mutations) {
            // For the sake of...observation...let's output the mutation to console to see how this all works
            mutations.forEach(function (mutation) {
                console.log(mutation.type);
            });
            resolve(mutations)
        });
        observer.observe(targetNode, observerConfig);
    })
} 

Dann erstellen wir einen generator function. Wenn Sie diese noch nicht verwendet haben, verpassen Sie sie - aber eine kurze Zusammenfassung lautet: Sie wird wie eine Synchronisierungsfunktion ausgeführt, und wenn sie einen yield <Promise> - Ausdruck findet, wartet sie in einem nicht blockierenden Zustand Mode für die Erfüllung des Versprechens ( Generatoren tun mehr als das, aber das interessiert uns hier).

// we'll declare our DOM node here, too
let targ = document.querySelector('#domNodeToWatch')

function* getMutation() {
    console.log("Starting")
    var mutations = yield startObservable(targ)
    console.log("done")
}

Ein schwieriger Punkt bei Generatoren ist, dass sie nicht wie eine normale Funktion "zurückkehren". Wir werden also eine Hilfsfunktion verwenden, um den Generator wie eine normale Funktion verwenden zu können. (wieder h/t bis dwb )

function runGenerator(g) {
    var it = g(), ret;

    // asynchronously iterate over generator
    (function iterate(val){
        ret = it.next( val );

        if (!ret.done) {
            // poor man's "is it a promise?" test
            if ("then" in ret.value) {
                // wait on the promise
                ret.value.then( iterate );
            }
            // immediate value: just send right back in
            else {
                // avoid synchronous recursion
                setTimeout( function(){
                    iterate( ret.value );
                }, 0 );
            }
        }
    })();
}

Führen Sie dann zu einem beliebigen Zeitpunkt, bevor die erwartete DOM-Mutation auftreten kann, einfach runGenerator(getMutation) aus.

Jetzt können Sie DOM-Mutationen in einen synchronen Steuerungsfluss integrieren. Wie wäre es damit?.

9
Brandon

Es gibt eine vielversprechende Javascript-Bibliothek namens Arrive, die wie eine großartige Möglichkeit aussieht, die Mutationsbeobachter zu nutzen, sobald die Browserunterstützung alltäglich ist.

https://github.com/uzairfarooq/arrive/

8
Dave Kiss

Schauen Sie sich dieses Plugin an, das genau das tut - jquery.initialize

Es funktioniert genau wie die .each-Funktion. Der Unterschied besteht darin, dass Sie den von Ihnen eingegebenen Selektor nach neuen Elementen suchen, die in der Zukunft mit diesem Selektor hinzugefügt werden, und diese initialisieren

Initialisieren sieht so aus

$(".some-element").initialize( function(){
    $(this).css("color", "blue");
});

Wenn nun ein neuer Elementzuordnungs-.some-element-Selektor auf der Seite erscheint, wird er sofort instanziert. 

Die Art und Weise, wie neue Elemente hinzugefügt werden, ist nicht wichtig, Sie müssen sich nicht um Rückrufe usw. kümmern.

Wenn Sie also ein neues Element hinzufügen möchten:

$("<div/>").addClass('some-element').appendTo("body"); //new element will have blue color!

es wird sofort initialisiert.

Plugin basiert auf MutationObserver

3
pie6k

Eine reine Javascript-Lösung (ohne jQuery):

const SEARCH_DELAY = 100; // in ms

// it may run indefinitely. TODO: make it cancellable, using Promise's `reject`
function waitForElementToBeAdded(cssSelector) {
  return new Promise((resolve) => {
    const interval = setInterval(() => {
      if (element = document.querySelector(cssSelector)) {
        clearInterval(interval);
        resolve(element);
      }
    }, SEARCH_DELAY);
  });
}

console.log(await waitForElementToBeAdded('#main'));
0
vedant