Tim Tim - 5 months ago 22
HTML Question

MutationObserver and Shadow DOM

I'm using Polymer's ShadowDOM and

MutationObserver
polyfills and need to:


  • Detect when a
    HTMLCanvasElement
    is inserted so that I can perform layout (its width and height are undetermined through
    offsetWidth
    /
    offsetHeight
    when detached from the DOM tree)

  • Detect when the element is removed so I can halt its
    requestAnimationFrame
    loop



Traditionally, without Shadow DOM, this works as follows:


  1. Attach
    MutationObserver
    to
    document.body
    and perform
    querySelectorAll
    for any canvas elements

  2. Perform some method, e.g.
    layoutNode
    on these elements

  3. If in the animation loop
    document.body.contains(node)
    returns
    false
    , then the node has been removed from the DOM



When using Shadow DOM I can get around the shadow dom boundaries by performing (what seems to be very inefficient) scans across all elements in the DOM that have roots which have been added, and performing
layoutNode
on any shadow dom nodes inheriting from
HTMLCanvasElement
.

How do I check from the animation loop of the canvas that this node is still in the DOM tree?

Is there a better API to use for detecting when a DOM node has been inserted?

(NB. MutationEvents are unavailable using Polymer's CustomElements polyfill.)

Tim Tim
Answer

I can use the following function attached to a Node to check whether the node is eventually rooted (through multiple shadow dom boundaries) at a given document, or the current document if no document is specified. This should be as efficient as a JS-based root.contains(node) call.

Object.defineProperty(Node.prototype, 'isAttachedToDocument', {
    configurable: true,
    enumerable: false,
    writable: true,
    value: function(document) {
        document = document || window.document;
        var el = this;
        while(el.parentNode || el.host) el = el.parentNode || el.host;
        return (el.impl || el) === document;
    }
});
Comments