javascript 如何判断一个元素是否在影子DOM中?

swvgeqrz  于 2023-01-24  发布在  Java
关注(0)|答案(7)|浏览(209)

我在一个项目中使用了阴影DOM(不是通过多边形填充),我想检测一个给定的element是否包含在阴影DOM或光照DOM中。
我已经查看了元素的所有属性,但似乎没有任何属性会根据元素所在的DOM类型而变化。
如何确定一个元素是阴影DOM还是光照DOM的一部分?
下面是一个示例,说明了针对此问题所考虑的“阴影DOM”和“轻型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>
yacmzcpb

yacmzcpb1#

如果你调用一个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;
}
    • 编辑**

Jeremy Banks提出了另一种循环方式,这种方式与我的方式略有不同:它还会检查传递的节点本身,我没有这么做。

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

一个二个一个一个

vhmi4jdf

vhmi4jdf2#

您可以检查元素是否具有影子父元素,如下所示:

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

这里使用的是instanceof而不是.toString()

ui7jx7zq

ui7jx7zq3#

警告:弃用风险️ Warning: Deprecation Risk

::shadow伪元素在动态选择器配置文件中已被弃用并将从中删除。下面的方法只要求它保留在静态选择器配置文件中,但将来也 * 可能 * 弃用并将其删除。Discussions are ongoing
我们可以使用Element 's .matches() method来确定一个元素是否附加到了影子DOM。
当且仅当元素在影子DOM中时,我们才能够通过使用选择器:host来识别具有影子DOM的元素,使用::shadow来查找那些影子DOM,使用*并匹配任何后代来匹配它。

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

x一个一个一个一个x一个一个二个x

os8fio9y

os8fio9y4#

shadowDOM中的元素可以使用getRootNode找到,如下所示。

function isInShadow(node) {
   return node.getRootNode() instanceof ShadowRoot;
}
xhv8bpkk

xhv8bpkk5#

让我们来了解灯光穹顶:
Light DOM是用户提供的托管影子根的元素的DOM。更多信息请阅读polymer-project。
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>

根据你的问题:
如果你想知道元素是否在影子根中,你只需要从文档中抓取元素。

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');
}
    • 唯一前面没有阴影根的Light DOM是文档的一部分,因为Light DOM是相对的,如上所示。**
    • 它不能向后**:如果文档的一部分根本不在Light DOM中。你需要检查是否有一个祖先托管了一个影子根,就像 * Leo * 建议的那样。

你可以使用这种方法来处理其他元素,只要用"my-custom-element"替换"document",然后测试div#LDofMCE是否在相对于"my-custom-element"的Light DOM中。
由于缺乏关于为什么你需要这些信息的信息,我无法接近...

    • 编辑:**
    • 它不能向后运行**应理解如下:
    • 此元素是否在影子根中?**:contains()或来自Leo的isInShadow(node)方法传递答案。

"倒退"问题:* * 此元素是否在Light DOM中(如果您开始相对于文档进行搜索)?**:contains()不能提供答案,因为要在Light Dom中--其中一个元素祖先需要是影子宿主。
"直奔主题"

  • 灯光DOM是相对的。
  • 一个元素可以同时参与阴影根和光照DOM。没有"* 是阴影DOM的一部分还是光照DOM?*"
htrmnn0y

htrmnn0y6#

这可以检查节点或元素是否在shadow dom中,并且适用于iframe

/**
 * @param {!Node} node
 * @return {!boolean}
 */
function isInShadowRoot(node) {
  return node.getRootNode().constructor.name === "ShadowRoot";
}

或使用示例

const inShadow = node.getRootNode() instanceof node.ownerDocument.defaultView.ShadowRoot
qnakjoqk

qnakjoqk7#

您可以通过执行以下操作来检查shadowDOM中是否存在任何元素:

/** element can be any HTMLELement or Node **/

const root = element && element.getRootNode();
const isOnShadowDOM = root instanceof ShadowRoot;
  • 第一行告诉我们哪个元素是根父元素,例如,一个lightDOM元素的根通常是#document,而一个阴影元素的根是#shadow-root
  • 第二行告诉我们这个根元素是否是shadowDOM,这里我们简单的检查根元素是否是ShadowRoot的一个stance,如果是,我们的常量就是true,否则就是false

相关问题