Czy istnieje moduł nasłuchujący zmiany DOM JavaScript / jQuery?
402
Zasadniczo chcę, aby skrypt był wykonywany, gdy treść DIVzmiany. Ponieważ skrypty są osobne (skrypt treści w rozszerzeniu Chrome i skrypcie strony internetowej), potrzebuję sposobu, aby po prostu obserwować zmiany w stanie DOM. Mógłbym skonfigurować odpytywanie, ale to wydaje się niechlujne.
Przez długi czas zdarzenia mutacji DOM3 były najlepszym dostępnym rozwiązaniem, ale były przestarzałe ze względu na wydajność. Obserwatorzy mutacji DOM4 zastępują przestarzałe zdarzenia mutacji DOM3. Są one obecnie zaimplementowane w nowoczesnych przeglądarkach jako MutationObserver(lub jako prefiks dostawcy WebKitMutationObserverw starych wersjach Chrome):
MutationObserver= window.MutationObserver|| window.WebKitMutationObserver;var observer =newMutationObserver(function(mutations, observer){// fired when a mutation occurs
console.log(mutations, observer);// ...});// define what element should be observed by the observer// and what types of mutations trigger the callback
observer.observe(document,{
subtree:true,
attributes:true//...});
Ten przykład nasłuchuje zmian DOM w documentcałym poddrzewie i będzie odpalał zmiany atrybutów elementu, a także zmiany strukturalne. Wersja robocza ma pełną listę poprawnych właściwości detektora mutacji :
childList
Ustaw, trueczy mutacje u dzieci docelowych mają być obserwowane.
atrybuty
Ustaw, trueczy mutacje atrybutów celu mają być obserwowane.
characterData
Ustaw, trueczy mutacje danych celu mają być obserwowane.
poddrzewo
Ustaw, trueczy mutacje mają nie tylko celować, ale także potomków celu mają być obserwowane.
attributeOldValue
Ustawiony na trueif attributesjest ustawiony na wartość true, a wartość atrybutu celu przed zarejestrowaniem mutacji.
characterDataOldValue
Ustawiony na trueif characterDatajest ustawiony na wartość true i dane celu przed zarejestrowaniem mutacji.
attributeFilter
Ustaw na listę lokalnych nazw atrybutów (bez przestrzeni nazw), jeśli nie wszystkie mutacje atrybutów muszą być przestrzegane.
(Ta lista jest aktualna od kwietnia 2014 r .; możesz sprawdzić specyfikację pod kątem zmian).
@AshrafBashir Widzę próbkę działającą poprawnie w Firefoksie 19.0.2: Widzę ([{}])zalogowany do konsoli, która pokazuje oczekiwane MutationRecordpo kliknięciu. Sprawdź ponownie, ponieważ mogła to być tymczasowa awaria techniczna JSFiddle. Nie testowałem go jeszcze w IE, ponieważ nie mam IE 10, który jest obecnie jedyną wersją obsługującą zdarzenia mutacji.
apsillers
1
Właśnie opublikowałem odpowiedź, która działa w IE10 + i przeważnie na cokolwiek innego.
naugtur
1
Wygląda na to, że specyfikacja nie ma już zielonego pola z listą opcji obserwatora mutacji. Wymienia opcje w sekcji 5.3.1 i opisuje je nieco poniżej.
LS
2
@LS Dzięki, zaktualizowałem link, usunąłem trochę o zielonym polu i zredagowałem całą listę do mojej odpowiedzi (na wszelki wypadek zepsucia linku w przyszłości).
Ta odpowiedź jest już nieaktualna. Zobacz odpowiedź apsillerów .
Ponieważ dotyczy to rozszerzenia Chrome, równie dobrze możesz użyć standardowego zdarzenia DOM - DOMSubtreeModified. Zobacz obsługę tego wydarzenia w różnych przeglądarkach. Jest obsługiwany w Chrome od wersji 1.0.
Nadal działa, jeśli budujesz rozszerzenia chromowane. nieoceniony.
concept47
49
Wiele witryn używa AJAX do dynamicznego dodawania / pokazywania / zmiany treści. Czasami jest używany zamiast nawigacji w witrynie, więc bieżący adres URL jest programowo zmieniany, a skrypty treści nie są automatycznie wykonywane przez przeglądarkę, ponieważ strona nie jest w całości pobierana ze zdalnego serwera.
Dostępne w JS metody wykrywania zmian strony dostępne w skrypcie treści .
MutationObserver ( dokumenty ), aby dosłownie wykryć zmiany DOM:
Okresowe sprawdzanie DOM za pomocą setInterval :
Oczywiście będzie to działać tylko wtedy, gdy będziesz czekać na pojawienie się określonego elementu identyfikowanego przez jego identyfikator / selektor, i nie pozwoli ci na powszechne wykrywanie nowej dynamicznie dodanej zawartości, chyba że wymyślisz jakiś odcisk palca istniejąca zawartość.
document.head.appendChild(document.createElement('script')).text ='('+function(){// injected DOM script is not a content script anymore, // it can modify objects and functions of the pagevar _pushState = history.pushState;
history.pushState =function(state, title, url){
_pushState.call(this, state, title, url);
window.dispatchEvent(newCustomEvent('state-changed',{detail: state}));};// repeat the above for replaceState too}+')(); this.remove();';// remove the DOM script element// And here content script listens to our DOM script custom events
window.addEventListener('state-changed',function(e){
console.log('History state changed', e.detail, location.hash);
doSomething();});
Inne podejście w zależności od tego, jak zmieniasz div. Jeśli używasz JQuery do zmiany zawartości div za pomocą metody html (), możesz rozszerzyć tę metodę i wywołać funkcję rejestracji za każdym razem, gdy wstawisz html do div.
(function( $, oldHtmlMethod ){// Override the core html method in the jQuery object.
$.fn.html =function(){// Execute the original HTML method using the// augmented arguments collection.var results = oldHtmlMethod.apply(this, arguments );
com.invisibility.elements.findAndRegisterElements(this);return results;};})( jQuery, jQuery.fn.html );
Po prostu przechwytujemy wywołania html (), wywołujemy funkcję rejestracji, która w kontekście odnosi się do elementu docelowego, który otrzymuje nową treść, a następnie przekazujemy wywołanie oryginalnej funkcji jquery.html (). Pamiętaj o zwróceniu wyników oryginalnej metody html (), ponieważ JQuery spodziewa się tego w przypadku łączenia metod.
Oprócz „surowych” narzędzi udostępnianych przez MutationObserverAPI , istnieją biblioteki „wygody” do pracy z mutacjami DOM.
Zastanów się: MutationObserver reprezentuje każdą zmianę DOM pod względem poddrzewa. Jeśli więc na przykład czekasz na wstawienie określonego elementu, może on znajdować się głęboko w elementach potomnych mutations.mutation[i].addedNodes[j].
Innym problemem jest sytuacja, gdy własny kod w reakcji na mutacje zmienia DOM - często chcesz go odfiltrować.
Dobrą wygodną biblioteką, która rozwiązuje takie problemy, jest mutation-summary(zrzeczenie się odpowiedzialności: nie jestem autorem, tylko zadowolonym użytkownikiem), która pozwala określić zapytania dotyczące tego, co Cię interesuje, i uzyskać dokładnie to.
([{}])
zalogowany do konsoli, która pokazuje oczekiwaneMutationRecord
po kliknięciu. Sprawdź ponownie, ponieważ mogła to być tymczasowa awaria techniczna JSFiddle. Nie testowałem go jeszcze w IE, ponieważ nie mam IE 10, który jest obecnie jedyną wersją obsługującą zdarzenia mutacji.Edytować
Ta odpowiedź jest już nieaktualna. Zobacz odpowiedź apsillerów .
Ponieważ dotyczy to rozszerzenia Chrome, równie dobrze możesz użyć standardowego zdarzenia DOM -
DOMSubtreeModified
. Zobacz obsługę tego wydarzenia w różnych przeglądarkach. Jest obsługiwany w Chrome od wersji 1.0.Zobacz działający przykład tutaj .
źródło
Wiele witryn używa AJAX do dynamicznego dodawania / pokazywania / zmiany treści. Czasami jest używany zamiast nawigacji w witrynie, więc bieżący adres URL jest programowo zmieniany, a skrypty treści nie są automatycznie wykonywane przez przeglądarkę, ponieważ strona nie jest w całości pobierana ze zdalnego serwera.
Dostępne w JS metody wykrywania zmian strony dostępne w skrypcie treści .
MutationObserver ( dokumenty ), aby dosłownie wykryć zmiany DOM:
Detektor zdarzeń dla witryn sygnalizujących zmianę treści przez wysłanie zdarzenia DOM:
pjax:end
nadocument
używane przez wiele witryn opartych na pjax, np. GitHub,zobacz Jak uruchomić jQuery przed i po załadowaniu pjax?
message
nawindow
używane np. przez wyszukiwanie Google w przeglądarce Chrome,zobacz rozszerzenie Chrome wykrywa odświeżanie wyszukiwania Google
spfdone
nadocument
używane przez Youtube,zobacz Jak wykryć nawigację po stronie na Youtube i zmodyfikować HTML przed renderowaniem strony?
Okresowe sprawdzanie DOM za pomocą setInterval :
Oczywiście będzie to działać tylko wtedy, gdy będziesz czekać na pojawienie się określonego elementu identyfikowanego przez jego identyfikator / selektor, i nie pozwoli ci na powszechne wykrywanie nowej dynamicznie dodanej zawartości, chyba że wymyślisz jakiś odcisk palca istniejąca zawartość.
Interfejs API historii maskowania wewnątrz wstrzykiwanego skryptu DOM :
Słuchanie hashchange , wydarzeń popstate :
Specyficzne dla rozszerzeń: wykrywanie zmian adresów URL na stronie w tle / zdarzeniu .
Istnieją zaawansowane API do pracy z nawigacją: webNavigation , webRequest , ale użyjemy prostego detektora zdarzeń chrome.tabs.onUpdated , który wysyła komunikat do skryptu treści:
manifest.json:
deklaruj stronę w tle / zdarzenie
deklaruj uprawnienia do skryptu
dodawania .
"tabs"
background.js
content.js
źródło
Inne podejście w zależności od tego, jak zmieniasz div. Jeśli używasz JQuery do zmiany zawartości div za pomocą metody html (), możesz rozszerzyć tę metodę i wywołać funkcję rejestracji za każdym razem, gdy wstawisz html do div.
Po prostu przechwytujemy wywołania html (), wywołujemy funkcję rejestracji, która w kontekście odnosi się do elementu docelowego, który otrzymuje nową treść, a następnie przekazujemy wywołanie oryginalnej funkcji jquery.html (). Pamiętaj o zwróceniu wyników oryginalnej metody html (), ponieważ JQuery spodziewa się tego w przypadku łączenia metod.
Aby uzyskać więcej informacji o zastępowaniu i rozszerzaniu metod, sprawdź http://www.bennadel.com/blog/2009-Using-Self-Executing-Function-Arguments-To-Override-Core-jQuery-Methods.htm , gdzie Przekopałem funkcję zamknięcia. Sprawdź także samouczek wtyczek na stronie JQuery.
źródło
Oprócz „surowych” narzędzi udostępnianych przez
MutationObserver
API , istnieją biblioteki „wygody” do pracy z mutacjami DOM.Zastanów się: MutationObserver reprezentuje każdą zmianę DOM pod względem poddrzewa. Jeśli więc na przykład czekasz na wstawienie określonego elementu, może on znajdować się głęboko w elementach potomnych
mutations.mutation[i].addedNodes[j]
.Innym problemem jest sytuacja, gdy własny kod w reakcji na mutacje zmienia DOM - często chcesz go odfiltrować.
Dobrą wygodną biblioteką, która rozwiązuje takie problemy, jest
mutation-summary
(zrzeczenie się odpowiedzialności: nie jestem autorem, tylko zadowolonym użytkownikiem), która pozwala określić zapytania dotyczące tego, co Cię interesuje, i uzyskać dokładnie to.Podstawowy przykład użycia z dokumentów:
źródło