jquery wykrywający element div określonej klasy został dodany do DOM


90

Używam .on()do wiązania zdarzeń div, które są tworzone po załadowaniu strony. Działa dobrze w przypadku kliknięcia, klawisza myszy ... ale muszę wiedzieć, kiedy został dodany nowy element div klasy MyClass. Szukam tego:

$('#MyContainer').on({

  wascreated: function () { DoSomething($(this)); }

}, '.MyClass');

Jak mam to zrobic? Udało mi się napisać całą moją aplikację bez wtyczki i chcę, żeby tak zostało.

Dzięki.


Czy to Twój własny kod generuje elementy? Jeśli tak, możesz to sprawdzić w momencie tworzenia i odpowiednio postępować.
— Surreal Dreams

Tak, to prawda, ale dzięki .on () mogę wiązać zdarzenia w document.ready i nie muszę się wtedy martwić o powiązanie podczas generowania kodu HTML. Szukam tego samego zachowania z DoSomething.
— Francuz

możesz użyć $ ("div / your-selector"). hasClass ("MyClass"); aby sprawdzić, czy element div ma określoną klasę, czy nie. Myślę, że możesz użyć tego interfejsu API do użytku.
— KBN

.on () jest tylko dla wydarzeń. Możesz skonfigurować zdarzenie niestandardowe, ale nadal będziesz musiał wywołać to zdarzenie podczas tworzenia nowych elementów.
— Surreal Dreams

Odpowiedzi:


102

Wcześniej można było podłączyć się do domManipmetody jQuery, aby złapać wszystkie manipulacje jQuery dom i zobaczyć, które elementy zostały wstawione itp., Ale zespół jQuery zamknął to w jQuery 3.0+, ponieważ generalnie nie jest dobrym rozwiązaniem podłączanie się do metod jQuery w ten sposób, a oni ' sprawiliśmy, że domManipmetoda wewnętrzna nie jest już dostępna poza podstawowym kodem jQuery.

Zdarzenia mutacji również zostały wycofane, ponieważ wcześniej można było zrobić coś takiego

$(document).on('DOMNodeInserted', function(e) {
    if ( $(e.target).hasClass('MyClass') ) {
       //element with .MyClass was inserted.
    }
});

Należy tego unikać, a obecnie zamiast tego należy używać Obserwatorów Mutacji, które działałyby w ten sposób

var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        console.log(mutation)
        if (mutation.addedNodes && mutation.addedNodes.length > 0) {
            // element added to DOM
            var hasClass = [].some.call(mutation.addedNodes, function(el) {
                return el.classList.contains('MyClass')
            });
            if (hasClass) {
                // element has class `MyClass`
                console.log('element ".MyClass" added');
            }
        }
    });
});

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

observer.observe(document.body, config);

Firefox i webkit powinny być w porządku, ale obsługa tego jest dość słaba w IE. Powinien działać w IE9, ale prawdopodobnie nie tak bardzo w IE8. Wiem, że widziałem obejścia i tak naprawdę nie testowałem tego w IE, więc najpierw przetestuj, jeśli nie działa, sprawdź, czy istnieje obejście. Jest wtyczka, która wygląda tak, jakby dodawała tutaj obsługę IE , ale jej nie próbowałem, po prostu znalazłem ją w wyszukiwarce Google.
— adeneo

2
Początkowo użyłem Twojej odpowiedzi, ale fakt, że nie działała ona w różnych przeglądarkach, był problemem. Potem szybko znalazłem obejście, aby uniknąć tego problemu. A potem, kilka tygodni temu, problem wykrywania wstawiania węzłów powrócił w moim kodzie. Tym razem kod, który zamieściłem w mojej odpowiedzi, działa DOKŁADNIE tak, jak powinien, między przeglądarkami i nic nie zawiera błędów. Dlatego właśnie ustawiłem moją odpowiedź jako zaakceptowaną; tak działa SO, PO decyduje, którą odpowiedź zaakceptuje, a tłum głosuje na odpowiedzi. Z biegiem czasu ludzie będą głosować i decydować, która odpowiedź najbardziej im odpowiada.
— Frenchie

2
Chciałem też powiedzieć, że kilkakrotnie pomogłeś mi udzielając wysokiej jakości odpowiedzi, które uratowały mi dzień. Zmiana zaakceptowanej odpowiedzi na moją zależy wyłącznie od kodu i tego, jak pasuje do problemu, który musiałem rozwiązać.
— frenchie

otrzymano „Uncaught TypeError: Cannot read property 'contains' of undefined” z tym kodem
— gordie

53

Oto moja wtyczka, która dokładnie to robi - jquery.initialize

Użycie jest takie samo, jak w przypadku .eachfunkcji, ale w przypadku .initializefunkcji na elemencie, różnica .eachpolega na tym, że inicjalizuje elementy dodane w przyszłości bez dodatkowego kodu - bez względu na to, czy dodasz go za pomocą AJAX, czy cokolwiek innego.

Initialize ma dokładnie taką samą składnię jak w przypadku funkcji .each

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

Ale teraz, jeśli na stronie pojawi się nowy element pasujący do selektora niektórych elementów, zostanie on zainicjowany w trybie natychmiastowym. Sposób dodawania nowej pozycji nie jest ważny, nie musisz przejmować się żadnymi callbackami itp.

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

Plugin jest oparty na MutationObserver


Dziękuję bardzo.
— Brandon Harris

jak zatrzymać inicjalizację? Chcę przestać oglądać, gdy coś, czego szukałem, zostanie dodane ...
— Evgeny Vostok,

$ (". jakiś element"). initialize [..] jest przestarzałe. Użyj $ .initialize (". AddDialog", function () {$ ('. NoData'). Hide ();}); zamiast.
— Heimi

Czy możliwe jest wykonanie .initializefunkcji callback tylko dla elementów, które są dynamicznie dodawane (np. Przez Ajax) i pominięcie wywołania zwrotnego dla elementów już obecnych podczas ładowania strony? Próbuję dodać parametr do options, aby to osiągnąć, ale jak dotąd nie mam tego do pracy.
— Nevermore

Możesz o tym dodać problem na githubie. Na razie technicznie $('.myClass').addClass('ignore-initialize'); $.initialize('.myClass:not(.ignore-initialize)', callback);
— dało się

19

Po przejrzeniu tego i kilku innych postów próbowałem wydestylować to, co uważałem za najlepsze z każdego z nich, w coś prostego, co pozwoliło mi wykryć, kiedy wstawiana jest klasa elementów, a następnie działać na tych elementach .

function onElementInserted(containerSelector, elementSelector, callback) {

    var onMutationsObserved = function(mutations) {
        mutations.forEach(function(mutation) {
            if (mutation.addedNodes.length) {
                var elements = $(mutation.addedNodes).find(elementSelector);
                for (var i = 0, len = elements.length; i < len; i++) {
                    callback(elements[i]);
                }
            }
        });
    };

    var target = $(containerSelector)[0];
    var config = { childList: true, subtree: true };
    var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
    var observer = new MutationObserver(onMutationsObserved);    
    observer.observe(target, config);

}

onElementInserted('body', '.myTargetElement', function(element) {
    console.log(element);
});

Co ważne dla mnie, pozwala to na a) istnienie elementu docelowego na dowolnej głębokości w ramach „addedNodes” oraz b) możliwość obsługi elementu tylko przy jego pierwotnym wstawieniu (nie ma potrzeby przeszukiwania całego ustawienia dokumentu ani ignorowania „już przetworzonego”) flagi).


1
Twój stan powinien być if(mutation.addedNodes.length), bo addedNodesi removedNodestablice są zawsze w mutationrodzaju childList(sprawdzane w IE11, Chrome53, FF49). Wciąż +1, ponieważ twoja jest jedyną odpowiedzią, w której addedNodesjest brana pod uwagę ( callbackjest wywoływana tylko wtedy, gdy dodawany jest węzeł); nie tylko w tym wątku, ale w wielu innych. Wszyscy inni po prostu wywołują callbackfor all mutations, nawet jeśli węzeł jest usuwany.
— Vivek Athalye

17

3 lata później doświadczenia, tak słucham „elementu pewnej klasy dodanego do DOM” : po prostu dodajesz hook do html()funkcji jQuery , na przykład:

function Start() {

   var OldHtml = window.jQuery.fn.html;

   window.jQuery.fn.html = function () {

     var EnhancedHtml = OldHtml.apply(this, arguments);

     if (arguments.length && EnhancedHtml.find('.MyClass').length) {

         var TheElementAdded = EnhancedHtml.find('.MyClass'); //there it is
     }

     return EnhancedHtml;
   }
}

$(Start);

To działa, jeśli używasz jQuery, co robię. I nie polega na zdarzeniu specyficznym dla przeglądarkiDOMNodeInserted , które nie jest kompatybilne z różnymi przeglądarkami. Dodałem również tę samą implementację dla.prepend()

Ogólnie rzecz biorąc, działa to jak urok dla mnie i mam nadzieję, że dla ciebie też.


6
Hmm - wyjaśniłbym, że to działa, jeśli używasz wyłącznie htmlpomocnika jQuery do modyfikowania DOM, a nie tylko „używania jQuery” w ogóle. Elementy dodane za pomocą, powiedzmy, jQuery.appendnie wywołają tego zdarzenia.
— iameli

1
Tak, i dlatego wyjaśniłem, że dodałem tę samą implementację z .preprend () i jeśli używasz .append (), zrób to samo z .append ()
— frenchie

Istnieje znacznie szybsze podejście, używając animacji CSS3 . Biblioteka open source udostępnia również znacznie prostszy kod:insertionQ('#intercom-container').every(function(/element){ element.style.display = 'none'; });
— Dan Dascalescu

3
Dlaczego głosy przeciw ?? To faktycznie działa: bez wtyczki i bez hakerskiej funkcji setTimeout.
— Francuz

2
Za głosem - to poprawna opcja - dlaczego na świecie (!!!) została ona odrzucona ?????? Dan, animacje CSS3 nie są XBC: caniuse.com/#search=keyframes ; davidwalsh.name/detect-node-insertion .
— Cody

6

możesz użyć zdarzeń mutacji

http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-eventgroupings-mutationevents

EDYTOWAĆ

z MDN: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events

Przestarzałe Ta funkcja została usunięta z internetu. Chociaż niektóre przeglądarki nadal mogą go obsługiwać, jest w trakcie usuwania. Nie używaj go w starych lub nowych projektach. Strony lub aplikacje internetowe, które go używają, mogą się zepsuć w dowolnym momencie.

Obserwatorzy mutacji są proponowanym zamiennikiem zdarzeń mutacji w DOM4. Mają być zawarte w przeglądarkach Firefox 14 i Chrome 18.

https://developer.mozilla.org/en/docs/Web/API/MutationObserver

MutationObserverzapewnia programistom sposób reagowania na zmiany w DOM. Został zaprojektowany jako zamiennik zdarzeń mutacji zdefiniowanych w specyfikacji DOM3 Events.

Przykładowe użycie

Poniższy przykład pochodzi z http://hacks.mozilla.org/2012/05/dom-mutationobserver-reacting-to-dom-changes-without-killing-browser-performance/ .

// select the target node
var target = document.querySelector('#some-id');

// create an observer instance
var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    console.log(mutation.type);
  });    
});

// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };

// pass in the target node, as well as the observer options
observer.observe(target, config);

// later, you can stop observing
observer.disconnect();

2
Zdarzenia mutacji są prawie przestarzałe według mdn , na korzyść MutationObservers
— Olga

Teraz, gdy IE10 jest EOL, powinno być prawie bezpieczne, aby powiedzieć, że MutationObserver jest szeroko obsługiwany.
— rymo

0

Dwa dodatki do odpowiedzi adeneo:

(1) możemy zmienić linię

return el.classList.contains('MyClass');

Do

if( el.classList ) {
    return el.classList.contains('MyClass');
} else {
    return false;
}

Więc nie zobaczymy "Uncaught TypeError: Cannot read property 'contains' of undefined" błędu.

(2) dodatek subtree: truew configcelu znalezienia dodano węzłów rekurencyjnie wszystkich dodawanych pierwiastków.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.