Comment savoir si un élément est dans un DOM de l'ombre?
j'ai un projet où j'utilise l'ombre de façon domnative (pas à travers un polyfill). J'aimerais détecter si un element
est contenu dans un dom de l'ombre ou un DOM de la lumière.
j'ai examiné toutes les propriétés des éléments, mais il ne semble pas y en avoir qui varient en fonction du type de DOM dans lequel un élément se trouve.
Comment puis-je déterminer si un élément fait partie d'un DOM shadow ou d'un DOM light?
Voici un exemple de ce que est considéré comme " shadow DOM "et" light DOM " aux fins de cette question.
(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>
4 réponses
Si vous appelez un ShadowRoot toString()
méthode, il sera de retour "[object ShadowRoot]"
. De ce fait, voici ma démarche:
function isInShadow(node) {
var parent = (node && node.parentNode);
while(parent) {
if(parent.toString() === "[object ShadowRoot]") {
return true;
}
parent = parent.parentNode;
}
return false;
}
EDIT
Jeremy Banks suggère une approche dans un autre style de boucle. Cette approche est un peu différente de la mienne: elle vérifie aussi le noeud lui-même, ce que je n'ai pas fait.
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>
Փ Avertissement: Risque De Dépréciation
::shadow
pseudo-élément est déprécié et retiré du profil du sélecteur dynamique. L'approche ci-dessous exige seulement qu'il reste dans le profil du sélecteur statique, mais il aussi être déprécié et retiré dans le futur. des Discussions sont en cours.
nous pouvons utiliser Element
.matches()
méthode pour déterminer si un élément est attaché à un DOM shadow.
si et seulement si l'élément est dans un DOM shadow, nous pourrons l'apparier en utilisant le sélecteur :host
identifier les éléments qui ont un Shadow DOM, ::shadow
regarder dans ceux de l'ombre DOMs, et *
et pour correspondre à n'importe quel descendant.
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>
vous pouvez vérifier si un élément a un parent d'ombre comme ceci:
function hasShadowParent(element) {
while(element.parentNode && (element = element.parentNode)){
if(element instanceof ShadowRoot){
return true;
}
}
return false;
}
instanceof
.toString()
.
permet de comprendre la lumière Dom:
le DOM Light est le DOM fourni par l'utilisateur d'un élément qui héberge une racine d'ombre. Pour plus d'informations, lisez au polymère-projet.
https://www.polymer-project.org/platform/shadow-dom.html#shadow-dom-subtrees
cela signifie: Light DOM est toujours relativeancêtre suivant qui héberge une racine d'ombre.
un Élément peut être un une partie de la lumière dom d'un élément personnalisé, même si elle peut être une partie de l'ombre de la racine d'un autre élément personnalisé en même temps.
Exemple:
<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>
selon votre question:
Si vous voulez savoir si un élément est une ombre de la racine, il vous suffit de saisir l'élément de l' document.
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');
}
la seule lumière DOM qui n'est pas précédée d'une racine d'ombre est une partie du document, parce que la lumière DOM est relative comme indiqué ci-dessus.
Il ne marche pas à reculons: si sa partie du document n'est pas du tout en lumière. Vous devez vérifier si l'un des ancêtres héberge une racine D'ombre comme suggéré de Leo.
Vous pouvez utiliser cette approche avec d'autres éléments. Il suffit de remplacer le "document" par exemple "my-custom-element" et tester si div#LDofMCE
est relativement faible par rapport à "mon-custom-élément".
en raison du manque d'information sur pourquoi vous avez besoin de cette information Je ne peux pas me rapprocher...
EDIT:
Il ne marche pas à reculons doit être compris comme suit:
cet élément est-il dans une racine D'ombre?: document.contient () ou la méthode isInShadow(node) de Leo fournit la réponse.
"à l'envers" Question: cet élément est-il dans un DOM léger (dans le cas où vous commencez la recherche relative au document)?: domcument.contains () ne fournit pas la réponse parce que pour être dans un Dom lumière - un des éléments ancêtres doit être un hôte d'ombre.
le Point
- la lumière est relative.
- un élément peut prendre part à une racine d'ombre et à un dom de lumière en même temps. il n'y a pas de " fait partie d'un shadow DOM OR un peu de DOM?"