manejo ejemplos javascript html5 css-selectors shadow-dom

javascript - ejemplos - ¿Cómo puedo saber si un elemento está en un DOM de sombra?



innerhtml (4)

Tengo un proyecto en el que estoy usando el DOM de la sombra de forma nativa (no a través de un relleno múltiple). Me gustaría detectar si un element dado está contenido dentro de un DOM de sombra o un DOM de luz.

He revisado todas las propiedades de los elementos, pero no parece haber ninguna que varíe según el tipo de DOM en el que se encuentre.

¿Cómo puedo determinar si un elemento es parte de un DOM de sombra o un DOM de luz?

Este es un ejemplo de lo que se considera "sombra DOM" y "luz DOM" para el propósito de esta pregunta.

(light root) • Document (light) • HTML (light) | • BODY (light) | • DIV (shadow root) | • ShadowRoot (shadow) | • DIV (shadow) | • IFRAME (light root) | • Document (light) | • HTML (light) | | • BODY (light) | | • DIV (shadow root) | | • ShadowRoot (shadow) | | • DIV (none) | • [Unattached DIV of second Document] (none) • [Unattached DIV of first Document]

<!doctype html> <title> isInShadow() test document - can not run in Stack Exchange''s sandbox </title> <iframe src="about:blank"></iframe> <script> function isInShadow(element) { // TODO } function test() { // (light root) • Document // (light) • HTML var html = document.documentElement; console.assert(isInShadow(html) === false); // (light) | • BODY var body = document.body; console.assert(isInShadow(body) === false); // (light) | • DIV var div = document.createElement(''div''); body.appendChild(div); console.assert(isInShadow(div) === false); // (shadow root) | • ShadowRoot var divShadow = div.createShadowRoot(); var shadowDiv = document.createElement(''div''); divShadow.appendChild(shadowDiv); // (shadow) | • DIV console.assert(isInShadow(shadowDiv) === true); // (shadow) | • IFRAME var iframe = document.querySelector(''iframe''); shadowDiv.appendChild(iframe); console.assert(isInShadow(iframe) === true); // (light root) | • Document var iframeDocument = iframe.contentWindow.document; // (light) | • HTML var iframeHtml = iframeDocument.documentElement; console.assert(isInShadow(iframeHtml) === false); // (light) | | • BODY var iframeBody = iframeDocument.body; // console.assert(isInShadow(iframeHtml) === false); // (light) | | • DIV var iframeDiv = iframeDocument.createElement(''div''); iframeBody.appendChild(iframeDiv); console.assert(isInShadow(iframeDiv) === false); // (shadow root) | | • ShadowRoot var iframeDivShadow = iframeDiv.createShadowRoot(); // (shadow) | | • DIV var iframeDivShadowDiv = iframeDocument.createElement(''div''); iframeDivShadow.appendChild(iframeDivShadowDiv); console.assert(isInShadow(iframeDivShadowDiv) === true); // (none) | • [Unattached DIV of second Document] var iframeUnattached = iframeDocument.createElement(''div''); console.assert(Boolean(isInShadow(iframeUnattached)) === false); // (none) • [Unattached DIV of first Document] var rootUnattached = document.createElement(''div''); console.assert(Boolean(isInShadow(rootUnattached)) === false); } onload = function main() { console.group(''Testing''); try { test(); console.log(''Testing complete.''); } finally { console.groupEnd(); } } </script>


Warning️ Advertencia: Riesgo de Depredación

El pseudo-elemento ::shadow está en desuso y se elimina del perfil del selector dinámico . El enfoque a continuación solo requiere que permanezca en el perfil del selector estático, pero también puede ser desaprobado y eliminado en el futuro. Las discusiones están en curso .

Podemos usar el método .matches() Element para determinar si un elemento está conectado a un DOM de sombra.

Si y solo si el elemento está en un DOM de sombra, podremos hacerlo coincidir usando el selector :host para identificar los elementos que tienen un DOM de sombra, ::shadow para buscar en esos DOM de sombra, y * y coincidir con cualquier descendiente.

function isInShadow(element) { return element.matches('':host::shadow *''); }

function isInShadow(element) { return element.matches('':host::shadow *''); } console.group(''Testing''); var lightElement = document.querySelector(''div''); console.assert(isInShadow(lightElement) === false); var shadowChild = document.createElement(''div''); lightElement.createShadowRoot().appendChild(shadowChild); console.assert(isInShadow(shadowChild) === true); var orphanedElement = document.createElement(''div''); console.assert(isInShadow(orphanedElement) === false); var orphanedShadowChild = document.createElement(''div''); orphanedElement.createShadowRoot().appendChild(orphanedShadowChild); console.assert(isInShadow(orphanedShadowChild) === true); var fragmentChild = document.createElement(''div''); document.createDocumentFragment().appendChild(fragmentChild); console.assert(isInShadow(fragmentChild) === false); console.log(''Complete.''); console.groupEnd();

<div></div>


Puedes verificar si un elemento tiene un padre sombra como este:

function hasShadowParent(element) { while(element.parentNode && (element = element.parentNode)){ if(element instanceof ShadowRoot){ return true; } } return false; }

Esto usa instanceof sobre .toString() .


Si llama a un método toString() ShadowRoot, devolverá "[object ShadowRoot]" . De acuerdo con este hecho, aquí está mi enfoque:

function isInShadow(node) { var parent = (node && node.parentNode); while(parent) { if(parent.toString() === "[object ShadowRoot]") { return true; } parent = parent.parentNode; } return false; }

EDITAR

Jeremy Banks sugiere un enfoque en otro estilo de bucle. Este enfoque es un poco diferente del mío: también verifica el nodo pasado, lo que no hice.

function isInShadow(node) { for (; node; node = node.parentNode) { if (node.toString() === "[object ShadowRoot]") { return true; } } return false; }

function isInShadow(node) { for (; node; node = node.parentNode) { if (node.toString() === "[object ShadowRoot]") { return true; } } return false; } console.group(''Testing''); var lightElement = document.querySelector(''div''); console.assert(isInShadow(lightElement) === false); var shadowChild = document.createElement(''div''); lightElement.createShadowRoot().appendChild(shadowChild); console.assert(isInShadow(shadowChild) === true); var orphanedElement = document.createElement(''div''); console.assert(isInShadow(orphanedElement) === false); var orphanedShadowChild = document.createElement(''div''); orphanedElement.createShadowRoot().appendChild(orphanedShadowChild); console.assert(isInShadow(orphanedShadowChild) === true); var fragmentChild = document.createElement(''div''); document.createDocumentFragment().appendChild(fragmentChild); console.assert(isInShadow(fragmentChild) === false); console.log(''Complete.''); console.groupEnd();

<div></div>


Vamos a entender Light Dom:

Light DOM es el DOM proporcionado por el usuario de un elemento que aloja una raíz de sombra. Para más información lea en polímero-proyecto.

https://www.polymer-project.org/platform/shadow-dom.html#shadow-dom-subtrees

Esto significa que: Light DOM siempre es relativo al siguiente antepasado que alberga una raíz de sombra .

Un elemento puede ser una parte de la luz dom de un elemento personalizado, mientras que puede ser una parte de la raíz de sombra de otro elemento personalizado al mismo tiempo .

Ejemplo:

<my-custom-element> <shadowRoot> <custom-element> <div>I''m in Light DOM of "custom-element" and in Shadow Root of "my-custom-element" at same time</div> </custom-element> </shadowRoot> <div id="LDofMCE"> Im in Light DOM of "my-custom-element"</div> <my-custom-element>

Según tu pregunta:

Si desea saber si un elemento está en una raíz de la sombra , solo necesita sacar el elemento del documento .

var isInLD = document.contains(NodeRef); if(isInLD){ console.alert(''Element is in the only available "global Light DOM"(document)''); } else { console.log(''Element is hidden in the shadow dom of some element''); }

El único Light DOM que no está precedido por una raíz de sombra es parte del documento, porque Light DOM es relativo como se muestra arriba.

No funciona al revés : si su parte del documento no está en un Light DOM en absoluto. Debes comprobar si uno de los ancestros tiene una Raíz de sombra como lo sugiere Leo .

Puede utilizar este enfoque con otros elementos para. Simplemente reemplace el "documento" con, por ejemplo, "my-custom-element" y pruebe si el div#LDofMCE está en Light DOM en relación con "my-custom-element".

Debido a la falta de información sobre por qué necesita esta información, no puedo estar más cerca ...

EDITAR:

No funciona al revés, debe entenderse de la siguiente manera:

¿Es este elemento en una raíz de la sombra? : document.contains () o el método isInShadow (nodo) de Leo entregan la respuesta.

Pregunta "hacia atrás": ¿Este elemento está en un DOM Light (en caso de que empiece a buscar en relación con el documento)? : domcument.contains () no entrega la respuesta porque estar en un Dom de Luz: uno de los elementos que los ancestros deben ser un host de sombra.

Ve al punto

  • La luz DOM es relativa.
  • Un elemento puede participar en una raíz de sombra y en un dom de luz al mismo tiempo. no hay " es parte de un DOM de sombra O un DOM de luz? "