jQery виявлення div певного класу додано до DOM


90

Я використовую .on()для прив'язки подій div, які створюються після завантаження сторінки. Це чудово працює для клацання, введення миші ... але мені потрібно знати, коли додано новий div класу MyClass. Я шукаю це:

$('#MyContainer').on({

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

}, '.MyClass');

Як це зробити? Я встиг написати всю свою програму без плагіна, і я хочу, щоб вона залишалася такою.

Дякую.


Це ваш власний код, який генерує елементи? Якщо так, ви можете перевірити під час його створення і діяти відповідно.
сюрреалістичні мрії

Так, це правда, але за допомогою .on () я можу прив’язувати події в document.ready, і тоді мені не доведеться турбуватися про прив’язку, коли я створюю HTML. Я шукаю таку ж поведінку з DoSomething.
французька

ви можете використовувати $ ("div / your-selector"). hasClass ("MyClass"); щоб перевірити, чи має div конкретний клас чи ні. Я думаю, ви могли б використати цей api для свого використання.
KBN

.on () призначений лише для подій. Ви можете налаштувати спеціальну подію, але вам все одно доведеться активувати цю подію, коли ви створюєте нові елементи.
Сюрреалістичні мрії

Відповіді:


103

Раніше можна було підключити domManipметод jQuery, щоб вловити всі маніпуляції з jQuery dom і побачити, які елементи вставлені і т. Д., Але команда jQuery закрила це в jQuery 3.0+, оскільки, як правило, не є гарним рішенням підключати методи jQuery таким чином, і вони ' я зробив це так, що внутрішній domManipметод більше не доступний поза основним кодом jQuery.

Події мутацій також застаріли, оскільки раніше можна було зробити щось подібне

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

цього слід уникати, і сьогодні замість цього слід використовувати спостерігачів мутацій, які працювали б так

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 та webkit мають бути майже в порядку, але підтримка цього дещо погана в IE. Це повинно працювати в IE9, але, мабуть, не так сильно в IE8. Я знаю, що бачив обхідні шляхи, і я насправді не тестував цього в IE, тому спершу протестуйте його, якщо він не працює, то подивіться, чи є обхідне рішення. Існує плагін, схожий на те, що він додає тут підтримку IE , але ще не пробував, просто знайшов його в пошуку Google.
adeneo

2
Спочатку я використав вашу відповідь, але той факт, що він не працював у різних браузерах, був проблемою. Потім я швидко придумав робоче рішення, щоб уникнути цієї проблеми. А потім, кілька тижнів тому, це питання виявлення вставки вузла знову повернулося до мого коду. Цього разу код, який я розмістив у своїй відповіді, працює ТОЧНО так, як і слід, крос-браузер і нічого не глючить. Ось чому я переніс свою відповідь як прийняту; ось як працює ТАК, ОП вирішує, яку відповідь він приймає, і натовп голосує за відповіді. З часом люди проголосують і вирішать, яка відповідь їм найбільше підходить.
французька

2
А також, я хотів сказати, що ви кілька разів допомагали мені якісними відповідями, які врятували мені день. Зміна прийнятої відповіді на мою суто залежить від коду та того, як він відповідає проблемі, яку мені довелося вирішити.
французька

отримав "Uncaught TypeError: Не вдається прочитати властивість 'contains' of undefined" за допомогою цього коду
gordie

53

Ось мій плагін, який робить це дуже точно - jquery.initialize

Useage такий самий, як ви використовуєте .eachфункцію, але з .initializeфункцією на елементі, відмінністю від того .each, що він також ініціалізує елементи, додані в майбутньому, без будь-якого додаткового коду - незалежно від того, додаєте ви його за допомогою AJAX або чогось іншого.

Ініціалізація має точно такий самий синтаксис, як і для .each функції

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

Але тепер, якщо на сторінці з'явиться новий елемент, що відповідає селектору .some-element, він буде ініціалізований миттєво. Спосіб додавання нового елемента не важливий, вам не потрібно дбати про будь-які зворотні дзвінки тощо.

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

Плагін базується на MutationObserver


Дуже дякую.
Брендон Харріс

як зупинити ініціалізацію? Я хочу припинити перегляд, як тільки додано те, що шукав ...
Євген Восток

$ (". some-element"). ініціалізація [..] застаріла. Використовуйте $ .initialize (". AddDialog", function () {$ ('. NoData'). Hide ();}); замість цього.
Хеймі

Чи можна виконати .initializeфункцію callback лише для елементів, які динамічно додаються (наприклад, через Ajax), і пропустити зворотний виклик для елементів, які вже є при первісному завантаженні сторінки? Я намагаюся додати параметр options, щоб досягти цього, але поки що я не маю цього працювати.
Ніколи більше

Ви можете додати випуск на github про це. Поки що технічно ви могли б це зробити$('.myClass').addClass('ignore-initialize'); $.initialize('.myClass:not(.ignore-initialize)', callback);
pie6k

19

Переглянувши цю та кілька інших публікацій, я спробував переробити те, що, на мою думку, було найкращим із кожного, у щось просте, що дозволило мені виявити, коли вставляється клас елементів, а потім діяти на ці елементи .

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);
});

Для мене важливо, що це дозволяє: а) цільовий елемент існувати на будь-якій глибині в межах "addedNodes" та б) можливість мати справу з елементом лише тоді, коли його спочатку вставили (не потрібно шукати весь параметр документа або ігнорувати "вже оброблений" прапори).


1
Ваша умова повинна полягати в if(mutation.addedNodes.length)тому, що addedNodesі removedNodesмасиви завжди є там mutationтипу childList(перевірено в IE11, Chrome53, FF49). Все-таки +1, оскільки ваша єдина відповідь, де addedNodesрозглядається ( callbackвикликається лише при додаванні вузла); не тільки на цій нитці, але й на багатьох інших нитках. Усі інші просто викликають callbackусі мутації, навіть якщо вузол видаляється.
Vivek Athalye

17

Через 3 роки досвіду, ось як я слухаю "елемент певного класу, доданий до DOM" : ви просто додаєте хук у функцію jQuery html(), наприклад:

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);

Це працює, якщо ви використовуєте jQuery, що я і роблю. І це не покладається на конкретну подію браузера DOMNodeInserted, яка не сумісна між браузерами. Я також додав ту саму реалізацію для.prepend()

Загалом, це працює як принада для мене, і, сподіваюся, і для вас теж.


6
Хм - я б пояснив, що це працює, якщо ви використовуєте лише htmlпомічник jQuery для модифікації DOM, а не просто "використання jQuery" загалом. Елементи, додані за допомогою, скажімо, jQuery.appendне ініціюють цю подію.
iameli

1
Так, і тому я пояснив, що додав ту саму реалізацію з .preprend (), і якщо ви використовуєте .append (), то зробіть те саме з .append ()
французька

Існує набагато швидший підхід, використовуючи анімацію CSS3 . Бібліотека з відкритим кодом також надає набагато простіший код:insertionQ('#intercom-container').every(function(/element){ element.style.display = 'none'; });
Ден Даскалеску

3
Чому голос проти? Це насправді працює: відсутність плагіна та відсутність функції hack setTimeout.
французька

2
Проголосовано - це дійсний варіант - чому у світі (!!!) це було проголосовано ?????? Ден, CSS3 Animations НЕ XBC: caniuse.com/#search=keyframes ; davidwalsh.name/detect-node-insertion .
Коді

6

ви можете використовувати події мутації

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

РЕДАГУВАТИ

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

Застаріла Ця функція вилучена з Інтернету. Хоча деякі браузери все ще можуть його підтримувати, він перебуває в стадії видалення. Не використовуйте його в старих або нових проектах. Сторінки або веб-програми, які використовують його, можуть зламатися в будь-який час.

Спостерігачі мутацій є запропонованою заміною подій мутації в DOM4. Вони повинні бути включені до Firefox 14 та Chrome 18.

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

MutationObserverнадає розробникам спосіб реагувати на зміни в DOM. Він розроблений як заміна подій мутації, визначених у специфікації подій DOM3.

Приклад використання

Наступний приклад взятий з 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
Згідно з mdn події мутації майже не підтримуються , на користь MutationObservers
Ольга

Тепер, коли IE10 є EOL, слід майже впевнено сказати, що MutationObserver широко підтримується.
rymo

0

Два доповнення до відповіді adeneo:

(1) ми можемо змінити рядок

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

До

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

Тож "Uncaught TypeError: Cannot read property 'contains' of undefined"помилки ми не побачимо .

(2) додати subtree: trueв configзнайти додані вузли рекурсивно у всіх доданих елементів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.