Событие при добавлении элемента на страницу


это уже обсуждалось здесь: Как выполнить действие, когда элемент добавляется на страницу с помощью Jquery?

ответчик предложил запускать пользовательское событие всякий раз, когда div был добавлен на страницу. Тем не менее, я пишу расширение Chrome и не имею доступа к источнику страницы. Какие у меня здесь варианты? Я думаю, в теории я мог бы просто использовать setTimeout чтобы постоянно искать присутствие элемента и добавить мое действие, если элемент есть.

7 108

7 ответов:

поскольку события мутации DOM теперь устаревший (см. Примечание внизу) с последними спецификациями, и у вас нет контроля над вставленными элементами, потому что они добавляются чужим кодом, ваш единственный вариант-постоянно проверять их.

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

после вызова этой функции она будет выполняться каждые xxx миллисекунды. Я выбрал 100, что составляет 1/10 (одну десятую) секунды. Если вам не нужно ловить элементы реального времени, это должно быть достаточно.

Edit

Как прокомментировал Бен Дэвис, спецификация DOM Level 4 вводит наблюдатели мутации (на Mozilla docs), которые заменяют устаревшие события изменения.

фактический ответ - "использовать наблюдателей мутаций" (как указано в этом вопросе:определение, если элемент HTML был добавлен в DOM динамически), однако поддержка (в частности, на IE) ограничена (http://caniuse.com/mutationobserver).

таким образом, фактический фактический ответ - "использовать наблюдателей мутаций.... в итоге. Но теперь идите с ответом Хосе Фаэти":)

вы также можете использовать события анимации CSS3, чтобы получать уведомления при добавлении определенного элемента в DOM:http://www.backalleycoder.com/2012/04/25/i-want-a-damnodeinserted/

можно использовать livequery плагин для jQuery. Вы можете предоставить выражение селектора, например:

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

каждый раз, когда кнопка removeItemButton класс добавлен сообщение появляется в строке состояния.

С точки зрения эффективности вы можете избежать этого, но в любом случае вы можете использовать плагин вместо создания собственных обработчиков событий.

пересмотреть ответа

ответ выше был только найти что элемент добавлено в DOM через плагин.

однако, скорее всего, a jQuery.on() подход был бы более уместным, например:

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

если у вас есть динамический контент, который должен реагировать на клики, например, лучше всего привязать события к родительскому контейнеру с помощью jQuery.on.

ETA 24 Apr 17 Я хотел бы упростить это немного с некоторыми async/await магия, как это делает его намного более лаконичен:

используя тот же обещанный-наблюдаемый:

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

ваша вызывающая функция может быть такой же простой, как:

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

если вы хотите добавить тайм-аут, вы можете использовать простой Promise.race pattern как показано ниже:

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

Оригинал

вы можно сделать это без библиотек, но вам придется использовать некоторые вещи ES6, поэтому будьте осведомлены о проблемах совместимости (т. е. если ваша аудитория в основном амиши, луддиты или, что еще хуже, пользователи IE8)

во-первых, мы будем использовать MutationObserver API для построения объекта-наблюдателя. Мы завернем этот объект в обещание, и resolve() когда обратный вызов срабатывает (h/t davidwalshblog)Дэвид Уолш блог статья о мутациях:

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

затем мы создадим generator function. Если вы еще не использовали их, то вы упускаете-но краткий обзор: он работает как функция синхронизации, и когда он находит yield <Promise> выражение, оно ожидает неблокирующим образом выполнения обещания (генераторы сделать больше, чем это, но это то, что нас интересует здесь).

// 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")
}

хитрая часть генераторов заключается в том, что они не "возвращаются", как нормальная функция. Итак, мы будем использовать вспомогательную функцию, чтобы иметь возможность использовать генератор как обычная функция. (опять же,h/t к 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 );
            }
        }
    })();
}

затем, в любой момент, прежде чем ожидаемая мутация DOM может произойти, просто запустите runGenerator(getMutation).

теперь вы можете интегрировать мутации DOM в поток управления синхронным стилем. Как насчет этого?

есть многообещающая библиотека javascript под названием Arrive, которая выглядит как отличный способ начать использовать преимущества наблюдателей мутаций, как только поддержка браузера станет обычным делом.

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

проверьте этот плагин, который делает именно это -jquery.инициализировать

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

инициализация выглядит вот так

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

но теперь, если новый элемент комбинационной .some-element селектор появится на странице, он будет мгновенно выполнено.

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

так что если бы вы добавили новый элемент, как:

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

он будет мгновенно запущен.

плагин основан на MutationObserver