Jedním z mých oblíbených webových triků bylo použití CSS a JavaScriptu k detekci vložení a odebrání uzlu DOM, podrobně popsáno v článku Detekce vložení uzlů DOM pomocí JavaScriptu a CSS animací. Technika a příspěvek na blogu byly zveřejněny v době, kdy jsme neměli rozumné API pro detekci takových událostí. V současné době máme MutationObserver
, API vytvořené pro efektivní detekci zátěže operací uzlů. Pojďme se podívat!
Základní MutationObserver
API
MutationObserver
API je pro mě trochu komplikované, ale zde je základní nastavení:
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); }); }); // Notify me of everything! var observerConfig = { attributes: true, childList: true, characterData: true }; // Node, config // In this case we'll listen to all changes to body and child nodes var targetNode = document.body; observer.observe(targetNode, observerConfig);
MutationObserver
se dá hodně používat , ale rozdělení je:
- Vytvořte instanci
MutationObserver
se zpětným voláním pro zpracování jakékoli události, která se mu dostane do cesty - Vytvořte sadu možností pro
MutationObserver
- Zavolejte na číslo
observe
metodaMutationObserver
instanci, předat jí uzel, který má naslouchat (..a jeho potomky) a seznam možností. - V době, kdy chcete přestat sledovat, zavolejte na
disconnect
MutationObserver
Možnosti
MDN poskytuje podrobnosti o možnostech pro MutationObserver
:
childList
:Nastavte na hodnotu true, pokud mají být dodrženy přidávání a odebírání podřízených prvků cílového uzlu (včetně textových uzlů).attributes
:Nastavte na hodnotu true, pokud mají být pozorovány mutace atributů cíle.characterData Set
:na hodnotu true, pokud mají být pozorovány mutace v datech cíle.subtree
:Nastavte na hodnotu true, pokud mají být pozorovány mutace nejen na cíl, ale také na jeho potomky.attributeOldValue
:Nastavte na hodnotu true, pokud jsou atributy nastaveny na hodnotu true a hodnota atributu cíle předtím, než je potřeba zaznamenat mutaci.characterDataOldValue
:Nastavte na hodnotu true, pokud je characterData nastaveno na hodnotu true a data cíle před tím, než je potřeba zaznamenat mutaci.attributeFilter
:Nastavte na pole lokálních názvů atributů (bez jmenného prostoru), pokud není třeba dodržet všechny mutace atributů.
To je třeba si uvědomit, když posloucháte jeden uzel a/nebo podřízené uzly!
MutationRecord: MutationObserver
Výsledky obslužného programu
Výsledný objekt, když je pozorována mutace, je také podrobně popsán:
type (String)
:Vrátí atributy, pokud byla mutace mutací atributu, CharacterData, pokud se jednalo o mutaci uzlu CharacterData, a childList, pokud šlo o mutaci stromu uzlů.target (Node)
:Vrátí uzel ovlivněné mutací v závislosti na typu. U atributů je to prvek, jehož atribut se změnil. Pro characterData je to uzel CharacterData. Pro childList je to uzel, jehož potomci se změnili.addedNodes (NodeList)
:Vrátí přidané uzly. Pokud nebyly přidány žádné uzly, bude prázdný seznam NodeList.removedNodes (NodeList)
:Vraťte odstraněné uzly. Pokud nebyly odstraněny žádné uzly, bude prázdný seznam NodeList.previousSibling (Node)
:Vrátí předchozího sourozence přidaných nebo odebraných uzlů nebo hodnotu null.nextSibling (Node)
:Vrátí dalšího sourozence přidaných nebo odebraných uzlů nebo hodnotu null.attributeName (String)
:Vrátí místní název změněného atributu nebo hodnotu null.attributeNamespace (String)
:Vrátí jmenný prostor změněného atributu nebo hodnotu null.oldValue (String)
:Vrácená hodnota závisí na typu. U atributů je to hodnota změněného atributu před změnou. Pro characterData jsou to data změněného uzlu před změnou. Pro childList má hodnotu null.
Páni. Pojďme se tedy podívat na některé reálné případy použití MutationObserver
.
Detekce při vložení uzlu
Případ použití v příspěvku Detect DOM Node Insertions with JavaScript and CSS Animations s detekce vložení uzlů, takže pojďme vytvořit úryvek, který detekuje vložení uzlů:
// Let's add a sample node to see what the MutationRecord looks like // document.body.appendChild(document.createElement('li')); { addedNodes: NodeList[1], // The added node is in this NodeList attributeName: null, attributeNamespace: null, nextSibling: null, oldValue: null, previousSibling: text, removedNodes: NodeList[0], target: body.document, type: "childList" }
Výsledný záznam MutationRecord zobrazuje addedNodes: NodeList[1]
, což znamená, že uzel byl přidán někam níže do stromu. type
je childList
.
Zjistit, kdy je uzel odstraněn
Odstraněním uzlu se zobrazí následující MutationRecord:
// Now let's explore the MutationRecord when a node is removed // document.body.removeChild(document.querySelector('div')) { addedNodes: NodeList[0], attributeName: null, attributeNamespace: null, nextSibling: text, oldValue: null, previousSibling: null, removedNodes: NodeList[1], // The removed node is in this NodeList target: body.document, type: "childList" }
Tato akce také zobrazuje type
z childList
ale nyní removeNodes
nyní má NodeList[1]
, NodeList
s odstraněným uzlem.
Zjistit změny atributů
Pokud se u kteréhokoli prvku změní atribut, budete o tom rychle vědět; MutationRecord zobrazí:
// What do attribute changes look like? // document.body.setAttribute('id', 'booooody'); { addedNodes: NodeList[0], attributeName: "id", attributeNamespace: null, nextSibling: null, oldValue: null, previousSibling: null, removedNodes: NodeList[0], target: body#booooody.document, type: "attributes" }
Všimněte si také, že target
zobrazí uzel, pro který byly změněny atributy. oldValue
zobrazí původní hodnotu a zatímco normální getAttribute
check poskytne vám novou hodnotu atributů.
Přestaňte poslouchat!
Pokud chcete napsat maximálně efektivní aplikaci, budete přidávat posluchače pouze na dobu, kterou potřebujete, a poté je odebírat, až budete hotovi:
observer.disconnect();
MutationObserver
instance má disconnect
způsob, jak přestat poslouchat. Vzhledem k tomu, že vaše aplikace může mít mnoho a mnoho operací DOM, možná budete chtít odpojit posluchače na dobu, po kterou uživatel interaguje se stránkou.
MutationObserver
API se zdá trochu podrobné, ale je výkonné, informativní a nakonec bez hackování. Geniální originální "hack" Daniela Buchnera poskytuje lepší podporu pro přidávání a odstraňování uzlů, ale MutationObserver
by měl být pravděpodobně použit, pokud je to možné.