DOM mutation events replacement
Since DOM mutation 开发者_StackOverflowis marked as deprecated by the w3c (see http://www.w3.org/TR/DOM-Level-3-Events/#events-mutationevents), is there an (fast) alternative way to detect attribute modification in the DOM ?
The reason that mutation events was deprecated was because of huge performance issues.
The replacement is Mutation Observers, look at http://updates.html5rocks.com/2012/02/Detect-DOM-changes-with-Mutation-Observers and https://developer.mozilla.org/en/DOM/DOM_Mutation_Observers
Information about mutations is delivered to observers as an ordered sequence of MutationRecords, representing an observed sequence of changes that have occurred
Sample usage:
var observer = new MutationObserver(function(mutationRecords) {
// Handle mutations
});
observer.observe(myNode,
{ // options:
subtree: true, // observe the subtree rooted at myNode
childList: true, // include information childNode insertion/removals
attribute: true // include information about changes to attributes within the subtree
});
This is supported in Chrome 18 and Firefox and Webkit nightly builds. Firefox 14 will also be supporting this feature.
A great replacement for the deprecated DOM* events is animationStart
in conjunction with CSS Animations. David Walsh writes about the method.
First, set up the keyframes and apply it to the elements you'd like to listen for (don't forget the vendor prefixes!):
@keyframes nodeInserted {
from { clip: rect(1px, auto, auto, auto); }
to { clip: rect(0px, auto, auto, auto); }
}
#parentElement > li {
animation-duration: 0.001s;
animation-name: nodeInserted;
}
Next, add the listener:
var insertListener = function(event){
if (event.animationName == "nodeInserted") {
// This is the debug for knowing our listener worked!
// event.target is the new node!
console.warn("Another node has been inserted! ", event, event.target);
}
}
document.addEventListener("animationstart", insertListener, false); // standard + firefox
document.addEventListener("MSAnimationStart", insertListener, false); // IE
document.addEventListener("webkitAnimationStart", insertListener, false); // Chrome + Safari
Ta-da! Here is David's demo. It works great for me on a Chrome extension that adds Facebook pictures to Google Voice (see content.css and injected.js).
A year later, there are the new and shiny Mutation Observers
from DOM Level 4 (follow the links there, they explain a lot!). Where a Mutation Event
fired a thousand times, MutationObserver
fires only once with all the modifications contained and accessible.
Works for (as of 2017/03):
- Firefox 14+
- IE 11
- Edge
- Opera 15+
- Chrome 26+ (18 till 25 prefixed,
window.WebKitMutationObserver
) - Safari 6.0 (prefixed,
window.WebKitMutationObserver
)
As far as I know there is no alternative (yet) so you are stuck with DOMAttrModified
which is only supported in Firefox and Opera. In IE you have the onpropertychanged
event but there is no way to get similar functionality in Chrome/Safari. There are a number of things you could do depending on what you are trying to accomplish and the browsers you are targetting:
- define getters and setters to the attributes you want to monitor
- override methods like
document.createAttribute
,attributes.setNamedItem
, ...
I've been working on a cross-browser solution myself but without much success. You should stay away from mutation events all together since they are not cross-browser and very slow. There are good reasons why they are deprecated. If you want to learn more read this:
- http://www.w3.org/2008/webapps/wiki/MutationReplacement
- http://www.quirksmode.org/dom/events/ > W3C events
- http://robertnyman.com/javascript/javascript-getters-setters.html
精彩评论