Skip to content

Instantly share code, notes, and snippets.

@labaneilers
Created December 8, 2017 19:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save labaneilers/80926ce3acc0517f90c5c40e3f2a1e91 to your computer and use it in GitHub Desktop.
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
(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