jquery, определяющий div определенного класса, был добавлен в DOM


92

Я использую .on()для привязки событий div, которые создаются после загрузки страницы. Он отлично работает для щелчка, мыши ... но мне нужно знать, когда был добавлен новый div класса MyClass. Я ищу это:

$('#MyContainer').on({

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

}, '.MyClass');

Как мне это сделать? Мне удалось написать все свое приложение без плагина, и я хочу, чтобы оно оставалось таким.

Благодарю.


Это ваш собственный код, который генерирует элементы? Если это так, вы можете проверить его при создании и действовать соответствующим образом.
— Surreal Dreams

Да, это правда, но с .on () я могу связывать события в document.ready, и тогда мне не нужно беспокоиться о привязке при создании HTML. Я ищу такое же поведение с DoSomething.
— frenchie

вы можете использовать $ ("div / your-selector"). hasClass ("MyClass"); чтобы проверить, имеет ли div конкретный класс или нет. Думаю, вы могли бы использовать этот api.
— KBN

.on () предназначен только для событий. Вы можете настроить собственное событие, но вам все равно придется запускать это событие при создании новых элементов.
— Surreal Dreams

Ответы:


105

Раньше можно было подключиться к 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.
    }
});

этого следует избегать, и сегодня вместо этого следует использовать Mutation Observers, которые будут работать следующим образом

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
Сначала я использовал ваш ответ, но тот факт, что он не работал в разных браузерах, был проблемой. Затем я быстро нашел способ избежать этой проблемы в первую очередь. А затем, несколько недель назад, эта проблема обнаружения вставки узла снова появилась в моем коде. На этот раз код, который я опубликовал в своем ответе, работает ТОЧНО, как и должен, кросс-браузерный и ничего не глючит. Вот почему я перенес свой ответ как принятый; вот как работает SO, OP решает, какой ответ он принимает, и толпа голосует за ответы. Со временем люди проголосуют и решат, какой ответ им подходит больше всего.
— Френчи

2
А также хочу сказать, что вы несколько раз помогали мне качественными ответами, которые спасли мне день. Изменение принятого ответа на мой зависит исключительно от кода и от того, как он соответствует проблеме, которую я должен был решить.
— frenchie

получил "Uncaught TypeError: Невозможно прочитать свойство 'contains' of undefined" с этим кодом
— Горди

53

Вот мой плагин, который именно это делает - jquery.initialize

Использование такое же, как если бы вы использовали .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 [..] устарел. Используйте $ .initialize (". AddDialog", function () {$ ('. NoData'). Hide ();}); вместо.
— Heimi

Можно ли выполнить .initializeфункцию callback только для элементов, которые добавляются динамически (например, через Ajax), и пропустить обратный вызов для элементов, уже присутствующих при первоначальной загрузке страницы? Я пытаюсь добавить параметр для optionsэтого, но пока у меня это не работает.
— Nevermore

Вы можете добавить проблему на github по этому поводу. А пока технически вы могли бы$('.myClass').addClass('ignore-initialize'); $.initialize('.myClass:not(.ignore-initialize)', callback);
— Адам Пьетрасиак

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

Для меня важно то, что это позволяет а) целевому элементу существовать на любой глубине в «добавленных узлах» и б) иметь дело с элементом только при его первоначальной вставке (нет необходимости искать во всем параметре документа или игнорировать «уже обработанный» флаги).


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

17

Спустя 3 года опыта я слушаю «элемент определенного класса, добавленный в DOM» : вы просто добавляете крючок в html()функцию jQuery , например:

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 ()
— frenchie

Есть гораздо более быстрый подход с использованием анимации CSS3 . Библиотека с открытым исходным кодом также предоставляет гораздо более простой код:insertionQ('#intercom-container').every(function(/element){ element.style.display = 'none'; });
— Дэн Даскалеску

3
Почему отрицательный? Это действительно работает: нет плагинов и нет хакерской функции setTimeout.
— frenchie

2
Проголосовали - это допустимый вариант - почему в мире (!!!) это было отклонено ?????? Дэн, CSS3-анимации - это не 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.