MutationObserver#
MutationObserver.observe()#
Metoda observe() rejestruje danego obserwatora zmian dla przekazanego węzła, z jednoczesnym określeniem szczegółowych kryteriów rejestracji przyszłych zmian w węźle (lub też jego potomkach). Obserwator zmian, na którym wywołano opisywaną metodę, staje się zarejestrowanym obserwatorem.
Opis działania#
Samo wywołanie i poszczególne jego części najlepiej objaśnić na zapisie składniowym:
mutationObserver.observe(target, options);gdzie poszczególne człony oznaczają:
- mutationObserver - obserwator zmian będący obiektem kontekstu.
- target - referencja do węzła, dla którego obserwator zmian jest rejestrowany.
- options - słownik typu
MutationObserverInitokreślający szczegółowe kryteria rejestrowanych zmian w węźle. W przypadku JS będzie to standardowy obiekt z następującymi właściwościami i wartościami:childList- boolowskietrueoznacza obserwację zmian w dzieciach posiadanych przez target. Zmiana w rzeczywistości oznacza modyfikację liczby dzieci w target, np. poprzez usunięcie lub dodanie nowych węzłów.attributes- boolowskietrueoznacza obserwację zmian w atrybutach posiadanych przez target. Zmiana w rzeczywistości obejmuje dodanie nowego atrybutu, usunięcie istniejącego atrybutu oraz zmianę wartości istniejącego atrybutu (nawet na taką samą). Można pominąć jeśli właściwościattributeOldValuei/lubattributeFilterzostały określone.characterData- boolowskietrueoznacza obserwację zmian w danych tekstowych posiadanych przez target. Zmiana w rzeczywistości oznacza modyfikację treści w węzłach znakowych. Można pominąć jeśli właściwośćcharacterDataOldValuezostała określona.subtree- boolowskietrueoznacza obserwację zmian nie tylko dla samego target, ale również w potomkach posiadanych przez target. Można zatem zarejestrować obserwatora bezpośrednio na target i jednocześnie obserwować zmiany dla wszystkich jego potomków.attributeOldValue- boolowskietrueoznacza (jeśli właściwośćattributesteż ma wartośćtruelub została pominięta) zapisanie wartości z atrybutów posiadanych przez target, jeszcze przed ich zmianą.characterDataOldValue- boolowskietrueoznacza (jeśli właściwośćcharacterDatateż ma wartośćtruelub została pominięta) zapisanie danych tekstowych posiadanych przez target, jeszcze przed ich zmianą.attributeFilter- sekwencja lokalnych nazw tych atrybutów (nie mogą mieć przestrzeni nazw), których zmiany będą obserwowane (właściwośćattributesteż musi mieć wartośćtruelub została pominięta). W przypadku JS odpowiednikiem sekwencji jest tablica.
Algorytm wywołania metody observe(target, options) nie jest skomplikowany. Dla lepszego zrozumienia tematu prezentuję go w całości:
- Jeśli właściwość
attributeOldValuelubattributeFilterw options jest obecna i właściwośćattributesw options jest nieobecna, to ustaw właściwośćattributesw options na boolowską wartośćtrue. - Jeśli właściwość
characterDataOldValuew options jest obecna i właściwośćcharacterDataw options jest nieobecna, to ustaw właściwośćcharacterDataw options na boolowską wartośćtrue. - Jeśli przynajmniej jedna z właściwości
childList,attributeslubcharacterDataw options nie ma boolowskiej wartościtrue, to zrzuć błądTypeError. - Jeśli właściwość
attributeOldValuew options ma boolowską wartośćtruei właściwośćattributesw options ma boolowską wartośćfalse, to zrzuć błądTypeError. - Jeśli właściwość
attributeFilterw options jest obecna i właściwośćattributesw options ma boolowską wartośćfalse, to zrzuć błądTypeError. - Jeśli właściwość
characterDataOldValuew options ma boolowską wartośćtruei właściwośćcharacterDataw options ma boolowską wartośćfalse, to zrzuć błądTypeError. Dla każdego (for each) zarejestrowanego obserwatora registered w liście zarejestrowanych obserwatorów skojarzonej z target, którego obserwatorem jest obiekt kontekstu, wykonaj poniższe podkroki:
- Usuń wszystkich przejściowych zarejestrowanych obserwatorów, których źródłem jest registered.
- Zastąp opcje w registered przez options.
- W przeciwnym razie dodaj nowego zarejestrowanego obserwatora do listy zarejestrowanych obserwatorów skojarzonej z target, dla którego obiekt kontekstu będzie obserwatorem i options będzie opcjami, a następnie dodaj target do listy węzłów skojarzonej z obiektem kontekstu, na których jest on rejestrowany.
Najciekawsza sytuacja ma miejsce w przypadku drugiego argumentu przekazanego do metody observe(). W ujęciu Web IDL mamy do czynienia ze słownikiem. Nie ma potrzeby wypisywania wszystkich właściwości w słowniku, no chyba że planujemy szerszą konkretyzację rejestrowanych zmian dla węzłów. Niektórzy członkowie słownika będą ustawiani automatycznie w zależności od wartości/obecności innych członków słownika (co widać w powyższym algorytmie). Jest to zamierzone i ma na celu zwiększenie elastyczności całego mechanizmu.
Prosty przykład:
<script>
// Tworzymy nowego obserwatora 'newObserver'
var newObserver = new MutationObserver(function(records, observer){
// W czasie wywołania funkcji zwrotnej mamy dostęp do:
// records - lista ze wszystkimi obiektami MutationRecord
// observer - nasz newObserwer
var getInfo = "";
var recordsLen = records.length;
for (var i = 0; i < recordsLen; i++){
var record = records[i];
getInfo += "<br><br>" + "records[" + i + "]: " + record
+ "<br>" + "record.type: " + record.type
+ "<br>" + "record.target: " + record.target
+ "<br>" + "record.addedNodes.length: " + record.addedNodes.length
+ "<br>" + "record.attributeName: " + record.attributeName
+ "<br>" + "record.attributeNamespace: " + record.attributeNamespace
+ "<br>" + "record.oldValue: " + record.oldValue;
}
document.documentElement.innerHTML += "Liczba zmian records.length: " + recordsLen
+ "<br><br>" + "Odczytujemy poszczególne dane każdej zmiany:"
+ getInfo;
});
// Tworzymy obiekt konfiguracyjny
var config = {
childList: true,
attributes: true,
attributeOldValue: true,
attributeFilter: ["id", "name"],
subtree: true,
characterDataOldValue: true
};
var new_P = document.createElement("P");
newObserver.observe(new_P, config); // rejestrujemy 'newObserver' na węźle 'new_P'
// Przeprowadzamy różne zmiany na węźle 'new_P' i jego zawartości
new_P.id = "id1";
new_P.id = "id2";
new_P.id = "id2";
new_P.className = "important"; // ten atrybut nie podlega obserwacji
new_P.appendChild(document.createElement("span"));
new_P.textContent = "Start";
new_P.childNodes[0].textContent = "Witam1";
new_P.childNodes[0].textContent = "Witam2";
new_P.childNodes[0].textContent = "Witam2";
</script>Metoda observe() pojawia się dopiero w specyfikacji DOM4.
Składnia Web IDL#
interface MutationObserver { void observe(Node target, MutationObserverInit options); }