28 javascript html5 css-selectors shadow-dom
我有一个项目,我在本地使用shadow DOM(不是通过polyfill).我想检测一个给定element是否包含在shadow DOM或light DOM中.
我已经查看了元素上的所有属性,但似乎没有根据元素所在的DOM类型而有所不同.
如何确定元素是影子DOM还是轻型DOM的一部分?
以下是针对此问题的"shadow DOM"和"light DOM"的示例.
(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>Run Code Online (Sandbox Code Playgroud)
Leo*_*Leo 31
如果你调用ShadowRoot的toString()方法,它将返回"[object ShadowRoot]".根据这个事实,这是我的方法:
function isInShadow(node) {
var parent = (node && node.parentNode);
while(parent) {
if(parent.toString() === "[object ShadowRoot]") {
return true;
}
parent = parent.parentNode;
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
编辑
杰里米·班克斯(Jeremy Banks)提出了另一种循环方式.这种方法与我的有点不同:它还检查传递的节点本身,我没有这样做.
function isInShadow(node) {
for (; node; node = node.parentNode) {
if (node.toString() === "[object ShadowRoot]") {
return true;
}
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
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();Run Code Online (Sandbox Code Playgroud)
<div></div>Run Code Online (Sandbox Code Playgroud)
par*_*par 16
ShadowDOM 中的元素可以使用getRootNode如下方式找到。
function isInShadow(node) {
return node.getRootNode() instanceof ShadowRoot;
}
Run Code Online (Sandbox Code Playgroud)
小智 8
⚠️警告:弃用风险
所述
::shadow伪元件在弃用,从动态选择配置文件被移除.下面的方法只要求它保留在静态选择器配置文件中,但它也可能在将来被弃用并删除.讨论正在进行中.
我们可以使用Element's .matches()方法来确定元素是否附加到影子DOM.
当且仅当元素在shadow DOM中时,我们才能通过使用选择器:host来识别具有Shadow DOM的元素,::shadow查看那些shadow DOM,以及*匹配任何后代.
function isInShadow(element) {
return element.matches(':host::shadow *');
}
Run Code Online (Sandbox Code Playgroud)
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();Run Code Online (Sandbox Code Playgroud)
<div></div>Run Code Online (Sandbox Code Playgroud)
您可以检查元素是否具有如下阴影父级:
function hasShadowParent(element) {
while(element.parentNode && (element = element.parentNode)){
if(element instanceof ShadowRoot){
return true;
}
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
这用完instanceof了.toString().
让我们了解Light Dom:
Light DOM是用户提供的托管阴影根的元素的DOM.欲了解更多信息,请阅读聚合物项目.
https://www.polymer-project.org/platform/shadow-dom.html#shadow-dom-subtrees
这意味着:Light DOM 始终 相对于承载阴影根的下一个祖先.
一个元件可以是自定义的元件的光DOM的一部分,同时也可以是另外的定制元素的阴影根的一部分在同一时间.
例:
<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>
Run Code Online (Sandbox Code Playgroud)
根据你的问题:
如果您想知道元素是否在阴影根中,您只需要从文档中获取元素.
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');
}
Run Code Online (Sandbox Code Playgroud)
唯一没有影子Root的Light DOM是文档的一部分,因为Light DOM是相对的,如上所示.
它不会倒退:如果它的部分文档根本不在Light DOM中.您需要检查其中一个祖先是否正在托管像Leo建议的影子根.
您可以将此方法与其他元素一起使用.只需将"document"替换为例如"my-custom-element",并测试div#LDofMCELight DOM是否相对于"my-custom-element".
由于缺乏有关您需要此信息的原因的信息,我无法接近...
编辑:
它不倒退 应该理解如下:
这个元素是暗影根吗?:来自Leo的document.contains()或isInShadow(node)方法提供了答案.
"向后"问题:这个元素是否在Light DOM中(如果你开始搜索相对于文档)?:domcument.contains()没有提供答案,因为要在Light Dom中 - 祖先需要成为影子主机的元素之一.
来点
| 归档时间: |
|
| 查看次数: |
4138 次 |
| 最近记录: |