2013-07-13 3 views
6

Мне нужно получить уведомление, когда элемент с классом «nav» создается при загрузке документа. Googling Я нашел MutationObservers и думал, что они будут идеальными, но я не могу заставить его работать.Посмотрите на создание элемента в сценарии greasemonkey?

// ==UserScript== 
// @name  ii-shortcuts 
// @namespace https://github.com/RedHatter 
// @include  * 
// @version  1 
// @run-at document-start 
// ==/UserScript== 

var observer = new MutationObserver(function(mutations) 
{ 
    mutations.forEach(function(mutation) 
    { 
     if (mutation.target.getAttribute('class') == 'nav') 
      GM_log('nav creation'); 
    });  
}); 
observer.observe(document, {subtree: true, attributes: true, attributeFilter: ['class']});  

Я также пробовал.

// ==UserScript== 
// @name  ii-shortcuts 
// @namespace https://github.com/RedHatter 
// @include  * 
// @version  1 
// @run-at document-start 
// ==/UserScript== 

var observer = new MutationObserver(function(mutations) 
{ 
    mutations.forEach(function(mutation) 
    { 
     if (mutation.addedNodes[0].getAttribute('class') == 'nav') 
      GM_log('nav creation'); 
    });  
}); 
observer.observe(document, {subtree: true, childList: true}); 

Но в последнем случае было создано «навигация» на странице загрузки. Что мне не хватает?

+0

@CrazyTrain Не accouding к [спецификации] (http://www.w3.org/html/wg/drafts /html/master/syntax.html#syntax) «События мутации DOM не должны запускаться для изменений, вызванных анализом UA документа ... Однако наблюдатели за мутациями срабатывают, как того требует спецификация DOM». – RedHatter

+0

вы можете использовать [arrival.js] (https://github.com/uzairfarooq/arrive), он обеспечивает приятный простой api для прослушивания создания элементов (использует MutationObserver внутри) –

+0

Хм ... выглядят очень красиво. Спасибо @UzairFarooq – RedHatter

ответ

6

Несколько выпусков (большие к малым):

  1. Когда документ является первым, статически загружен; события childList события, а не attributes события.

    Например,

    $("body").append ('<p id="foo" class="bar">Hiya!</p><p>blah</p>'); 
    

    генерирует одинchildList событие, в то время как последующая

    $("#foo").attr ("class", "bar2"); 
    

    генерирует событие attributes.

  2. Вероятность того, что mutation.addedNodes[0] содержит элемент с классом nav практически равны нулю. Это почти всегда текстовый узел.
    Вам необходимо проверить весь массив, PLUS target.

  3. Не используйте getAttribute('class') == 'nav' для проверки классов. Это вызовет исключения для узлов без функции getAttribute и пропустит элементы, имеющие более одного класса. EG: <p class="foo nav bar">...

    Используйте classList.contains() на соответствующих типах узлов.

  4. Используйте директиву @grant, если вы используете любые функции GM_, такие как GM_log(). В любом случае используйте грант, чтобы убедиться, что песочница остается включенной.

  5. Избегайте использования // @include *. Особенно с таймерами и наблюдателями это может привести к потере вашего браузера и вашей машины.

  6. Эта информация предназначена для Firefox. Хром имеет большие отличия в том, как он реализует наблюдателей Mutation. Этот код не будет работать в Chrome до загрузки страницы.


Собираем все вместе, сценарий становится:

// ==UserScript== 
// @name  _ii-shortcuts 
// @namespace https://github.com/RedHatter 
// @include  http://YOUR_SERVER.COM/YOUR_PATH/* 
// @run-at  document-start 
// @version  1 
// @grant  GM_log 
// ==/UserScript== 
/*- The @grant directive is needed to work around a design change 
    introduced in GM 1.0. It restores the sandbox. 
*/ 
var MutationObserver = window.MutationObserver; 
var myObserver  = new MutationObserver (mutationHandler); 
var obsConfig  = { 
    childList: true, attributes: true, 
    subtree: true, attributeFilter: ['class'] 
}; 

myObserver.observe (document, obsConfig); 

function mutationHandler (mutationRecords) { 

    mutationRecords.forEach (function (mutation) { 

     if ( mutation.type    == "childList" 
      && typeof mutation.addedNodes == "object" 
      && mutation.addedNodes.length 
     ) { 
      for (var J = 0, L = mutation.addedNodes.length; J < L; ++J) { 
       checkForCSS_Class (mutation.addedNodes[J], "nav"); 
      } 
     } 
     else if (mutation.type == "attributes") { 
      checkForCSS_Class (mutation.target, "nav"); 
     } 
    }); 
} 

function checkForCSS_Class (node, className) { 
    //-- Only process element nodes 
    if (node.nodeType === 1) { 
     if (node.classList.contains (className)) { 
      console.log (
       'New node with class "' + className + '" = ', node 
      ); 
      // YOUR CODE HERE 
      //GM_log ('nav creation'); 
     } 
    } 
} 
+0

Спасибо за советы! хотя я собирался добавить '@ grant', когда скрипт был выполнен (вы получите этот раздражающий поп в противном случае), и я только поместил' @include * ', потому что я не хотел показывать, на каком сайте я использовал скрипт на. – RedHatter

0

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

Так что следите за mutation.addedNodes, возвращающим нуль - в этом случае этот код не удастся. Попробуйте:

if (mutation.addedNodes && mutation.addedNodes[0].getAttribute('class') === 'nav') { 
    ... 

Объект мутации также имеет атрибут 'type', который вы можете использовать для получения дополнительной информации; вы читали документы API по адресу MDN? Есть несколько хороших примеров.

+0

Я пробовал код, ничего не меняю. Проблема заключается не в сбое сценария, а в том, что элемент с классом nav никогда не передается MutationObserver. И да, я прочитал документы. – RedHatter

+0

У вас есть тестовая страница с HTML, которую вы смотрите этим кодом? – Wheeyls

Смежные вопросы