2012-02-28 7 views
17

E 'possibile e come posso ascoltare le modifiche attraverso l'intero albero DOM con jQuery?jQuery: come ascoltare le modifiche al DOM?

Il mio problema specifico: Ho una funzione "tooltip" che visualizza il contenuto dell'attributo title in modo elegante quando si esegue un hover su qualsiasi elemento html. Quando si esegue il passaggio del mouse, tuttavia, in base allo standard, il browser esegue il rendering dello title nella propria casella. Vorrei sopprimere questo. Quindi, quello che ho pensato è di spostare il contenuto dell'attributo title in un attributo personalizzato (HTML5) data-title la prima volta che viene caricata la pagina, e quindi la mia funzione di suggerimento funzionerà con data-title.

Il problema è che in seguito potrei aggiungere/rimuovere/modificare l'HTML in modo dinamico, quindi ho bisogno di "rebind" quegli elementi - cambia di nuovo quel titolo. Sarebbe bello se ci fosse un ascoltatore di eventi che ascoltasse tali cambiamenti per me e rebind automaticamente gli elementi.

+0

possibile duplicato di [Come identificare quando il DOM è stato cambiato?] (Http://stackoverflow.com/questions/3744706/how-to-identify-when-the -dom-has-been-changed) –

+2

sembra come provare ad ascoltare ogni cambiamento nel DOM ... e cercare i tuoi elementi ogni volta sarebbe davvero costoso. – charlietfl

+0

possibile duplicato di [Esiste un listener di modifiche DOM jQuery?] (Http://stackoverflow.com/questions/2844565/is-there-a-jquery-dom-change-listener) – APerson

risposta

33

La mia ipotesi migliore è che si desidera ascoltare gli eventi di mutazione DOM. Puoi farlo tramite l'evento di mutazione DOM come qualsiasi normale evento javascript come un clic del mouse.

fare riferimento a questo: W3 MutationEvent

Esempio:

$("element-root").bind("DOMSubtreeModified", "CustomHandler"); 
+1

Non sono necessarie le virgolette sul gestore, è un modo per ottenere la funzione da associare all'evento. – MacMac

+1

questo codice potrebbe sembrare breve e dolce, ma il carico che carica sul browser è insufficiente per questo caso d'uso quando esistono soluzioni di delega degli eventi sotto – charlietfl

+0

Errore mio. Ho aggiunto le citazioni in fretta – nightf0x

2

[edito in risposta alle ricerche per utente Tony]

Così, senza codice aggiuntivo, questo è un po 'un colpo cieco , ma a me sembra che ci siano due cose a cui pensare qui: 1. il comportamento predefinito del tooltip del browser; 2. un DOM potenzialmente aggiornato e la possibilità che i tooltip personalizzati continuino a funzionare.

Per quanto riguarda il numero 1: quando si associa l'evento personalizzato all'elemento, è possibile utilizzare event.preventDefault() in modo che le descrizioni dei comandi non vengano visualizzate. Questo non funziona correttamente. Pertanto, la soluzione alternativa per continuare a utilizzare l'attributo "title" consiste nell'acquisire il valore, inserirlo nell'oggetto dati (la funzione $.data()) e quindi annullare il titolo con una stringa vuota (removeAttr è incoerente). Quindi, con il mouseleave, estrai il valore dall'oggetto dati e reinseriscilo nel titolo. Questa idea viene da qui: How to disable tooltip in the browser with jQuery?

Per quanto riguarda il n. 2: invece di re-binding sul cambiamento DOM, è sufficiente associare una volta a un elemento listener che non dovrebbe mai essere distrutto. Di solito questo è un elemento contenitore di qualche tipo, ma può anche essere document (approssimativo a .live() che ora è deprecato) se è davvero necessario un contenitore onnicomprensivo. Ecco un esempio che utilizza alcuni markup falso di mia invenzione:

var container = $('.section'); 

container.on('mouseenter', 'a', function() { 
    var $this = $(this); 
    var theTitle = $this.attr('title'); 
    $this.attr('title', ''); 
    $('#notatooltip').html(theTitle); 
    $.data(this, 'title', theTitle); 
}); 

container.on('mouseleave', 'a', function() { 
    $('#notatooltip').html(''); 
    var $this = $(this); 
    var storedTitle = $.data(this, 'title'); 
    $this.attr('title', storedTitle); 
}); 

mio markup irrealistico (solo per questo esempio) è qui:

<div class="section"> 
    <a href="#" title="foo">Hover this foo!</a> 
    <div id="notatooltip"></div> 
</div> 

E un violino è qui: http://jsfiddle.net/GVDqn/ o con qualche controlli di integrità: http://jsfiddle.net/GVDqn/1/

Probabilmente c'è un modo più ottimale per farlo (sinceramente non ho studiato se si potevano associare due funzioni separate per due eventi separati con un solo selettore), ma farà il trucco.

Non è necessario eseguire il reindirizzamento in base alla modifica DOM, il listener delegato lo gestirà automaticamente. E dovresti essere in grado di prevenire la funzionalità del tooltip di default semplicemente prevenendolo.

+0

approccio più sensibile qui! .... allora all'interno del mouseenter puoi verificare se il titolo è stato spostato in $ (questo) .data ('title') o no – charlietfl

+0

sarebbe stata la soluzione più elegante, ma sembra che 'preventDefault' NON impedisca di mostrare titoli su' mouseover' (almeno in Chrome) - http://code.google.com/p/chromium/issues/detail?id=42549 –

+0

@Tony Buona ricerca; Penso che sia fallito anche in Fx. Ho aggiornato con il nuovo codice. –

0

Come notato da Greg Pettit, si dovrebbe utilizzare la funzione on() sull'elemento.

Ciò che consente è di associare un selettore a un evento, quindi jQuery aggiungerà questo gestore di eventi quando gli oggetti restituiti dal selettore saranno disponibili.

Se si voleva una funzione di sparare su un mouse su evento e si voleva che il fuoco su tutti gli elementi con la classe di * FIELD_TITLE * si dovrebbe fare questo:

$('.field_title').bind('mouseenter', function() { doSomething(); }); 

In tal modo, il il mouse sopra l'evento su qualsiasi oggetto che abbia la classe di * field_title * ed esegua la funzione doSomething().

speranza che abbia un senso :)

+1

Hai un errore di battitura, dovrebbe essere '.bind ('mouseenter')' not '. ('mouseenter')'. – MacMac