Created
December 8, 2017 19:42
-
-
Save labaneilers/80926ce3acc0517f90c5c40e3f2a1e91 to your computer and use it in GitHub Desktop.
Listen and respond to DOM elements as they are added to prevent flicker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function(win) { | |
'use strict'; | |
var listeners = []; | |
var doc = win.document; | |
var MutationObserver = win.MutationObserver || win.WebKitMutationObserver; | |
var observer; | |
// Returns true if the specified node matches the selector | |
function matches(el, selector) { | |
var fn = el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector; | |
return fn ? fn.call(el, selector) : false; | |
} | |
// Adds a callback that will fire when a DOM node matching the selector is added to the DOM | |
function elementAdded(selector, fn) { | |
// Store the selector and callback to be monitored | |
listeners.push({ | |
selector: selector, | |
fn: fn | |
}); | |
if (!observer) { | |
// Watch for changes in the root document element | |
observer = new MutationObserver(check); | |
observer.observe(doc.documentElement, { | |
childList: true, | |
subtree: true | |
}); | |
} | |
} | |
// Private method to inspect all DOM mutations | |
function check(mutations) { | |
// Keep track if a listener has found its target node, | |
// so we can remove it and potentially short-circuit. | |
var removeListeners = false; | |
for (var i=0; i<mutations.length; i++) { | |
var mut = mutations[i]; | |
for (var j=0; j<mut.addedNodes.length; j++) { | |
var node = mut.addedNodes[j]; | |
// For each found DOM element, check it against each listener's selector | |
if (node.tagName) { | |
for (var k=0; k<listeners.length; k++) { | |
if (matches(node, listeners[k].selector)) { | |
if (listeners[k].fn.call(node, node) === true) { | |
listeners[k].complete = true; | |
removeListeners = true; | |
} | |
} | |
} | |
// If a listener found its target, remove it from the list of listeners. | |
if (removeListeners) { | |
listeners = listeners.filter(function(x) { return !x.complete; }); | |
removeListeners = false; | |
// All listeners found their target. Stop looking. | |
if (listeners.length === 0) { | |
observer.disconnect(); | |
return; | |
} | |
} | |
} | |
} | |
} | |
} | |
win.elementAdded = elementAdded; | |
})(this); | |
// Usage: | |
window.elementAdded("#merchContent_0", function(el) { | |
el.style.display = "none"; | |
// NOTE: Performance optimization: | |
// Returning true indicates the search for this element is successful, don't keep going. | |
return true; | |
}); | |
window.elementAdded(".header-logo", function(el) { | |
el.style.backgroundColor = "red"; | |
return true; | |
}); | |
// Here's a naive DOMContentLoaded event handler for comparison: | |
// This is causes flicker! | |
// document.addEventListener("DOMContentLoaded", function(event) { | |
// document.getElementById("merchContent_0").style.display = "none"; | |
// }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment