如何判断一个元素是否在影子 DOM 中?
我有一个项目,我在本地使用影子 DOM(而不是通过 polyfill).我想检测给定的 element
是否包含在 shadow DOM 或 light DOM 中.
我查看了元素的所有属性,但似乎没有任何根据元素所在的 DOM 类型而有所不同.
如何确定一个元素是阴影 DOM 还是光 DOM 的一部分?
<小时>以下是出于本问题的目的被认为是shadow DOM"和light DOM"的示例.
<上一页>(轻根) • 文档(浅色) • HTML(光) |• 身体(光) |• DIV(影根) |• 影子根(影子)|• 分区(影子)|• 框架(轻根) |• 文档(光) |• HTML(光) ||• 身体(光) ||• 分区(影根) ||• 影子根(影子)||• 分区(无)|• [第二个文档的未附加 DIV](无) • [第一个文档的未附加 DIV]<!doctype html><标题>isInShadow() 测试文档 - 无法在 Stack Exchange 的沙箱中运行</标题><iframe src="about:blank"></iframe><脚本>函数isInShadow(元素){//去做}功能测试() {//(轻根) • 文档//(浅色) • HTMLvar html = document.documentElement;console.assert(isInShadow(html) === false);//(光)|• 身体var body = document.body;console.assert(isInShadow(body) === false);//(光)|• DIVvar div = document.createElement('div');body.appendChild(div);console.assert(isInShadow(div) === false);//(影子根) |• 影子根var divShadow = div.createShadowRoot();var shadowDiv = document.createElement('div');divShadow.appendChild(shadowDiv);//(阴影) |• 分区console.assert(isInShadow(shadowDiv) === true);//(阴影) |• 框架var iframe = document.querySelector('iframe');shadowDiv.appendChild(iframe);console.assert(isInShadow(iframe) === true);//(轻根) |• 文档var iframeDocument = iframe.contentWindow.document;//(光)|• HTMLvar iframeHtml = iframeDocument.documentElement;console.assert(isInShadow(iframeHtml) === false);//(光)||• 身体var iframeBody = iframeDocument.body;//console.assert(isInShadow(iframeHtml) === false);//(光)||• 分区var iframeDiv = iframeDocument.createElement('div');iframeBody.appendChild(iframeDiv);console.assert(isInShadow(iframeDiv) === false);//(影子根) ||• 影子根var iframeDivShadow = iframeDiv.createShadowRoot();//(阴影) ||• 分区var iframeDivShadowDiv = iframeDocument.createElement('div');iframeDivShadow.appendChild(iframeDivShadowDiv);console.assert(isInShadow(iframeDivShadowDiv) === true);//(无) |• [第二个文档的未附加 DIV]var iframeUnattached = iframeDocument.createElement('div');console.assert(Boolean(isInShadow(iframeUnattached)) === false);//(无) • [第一个文档的未附加 DIV]var rootUnattached = document.createElement('div');console.assert(Boolean(isInShadow(rootUnattached)) === false);}加载 = 函数 main() {console.group('测试');尝试 {测试();console.log('测试完成.');} 最后 {控制台.groupEnd();}}</script>
解决方案如果调用ShadowRoot的toString()
方法,会返回"[object ShadowRoot]"
.根据这个事实,这是我的方法:
function isInShadow(node) {var parent = (node && node.parentNode);而(父){if(parent.toString() === "[object ShadowRoot]") {返回真;}父 = 父节点;}返回假;}
<小时>
编辑
Jeremy Banks 提出了另一种循环方式的方法.这种方法和我的有点不同:它还会检查传递的节点本身,而我没有这样做.
function isInShadow(node) {for (; node; node = node.parentNode) {if (node.toString() === "[object ShadowRoot]") {返回真;}}返回假;}
function isInShadow(node) {for (; node; node = node.parentNode) {if (node.toString() === "[object ShadowRoot]") {返回真;}}返回假;}console.group('测试');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('完成.');console.groupEnd();
<div></div>
I have a project where I'm using the shadow DOM natively (not through a polyfill). I'd like to detect if a given element
is contained within a shadow DOM or a light DOM.
I've looked through all of the properties on the elements, but there don't seem to be any which vary based on the type of DOM an element is in.
How can I determine if an element is part of a shadow DOM or a light DOM?
Here is an example of what is considered "shadow DOM" and "light DOM" for the purpose of this 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>
解决方案
If you call a ShadowRoot's toString()
method, it will return "[object ShadowRoot]"
. According to this fact, here's my approach:
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 suggests an approach in another style of looping. This approach is a little different from mine: it also checks the passed node itself, which I didn't do.
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>
相关文章