如何在Dart中从外部查询shadow DOM中的元素?

Tim*_*nov 14 css-selectors dart shadow-dom polymer dart-polymer

如何在shadow DOM中选择节点?请考虑以下示例:

"没有阴影"的DOM的结构

<app-element>
  #shadow-root
    <h2></h2>
    <content>
      #outside shadow
      <h2></h2>
    </content>
    <ui-button>
      #shadow-root
        <h2></h2>
  </ui-button>
</app-element>
Run Code Online (Sandbox Code Playgroud)

的index.html

<body>
<app-element>
  <!-- OK: querySelect('app-element').querySelect('h2') -->
  <!-- OK: querySelect('app-element h2') -->
  <!-- There is no problem to select it -->
  <h2>app-element > content > h2</h2>
</app-element>
</body>
Run Code Online (Sandbox Code Playgroud)

templates.html

<polymer-element name="ui-button" noscript>
  <template>
    <!-- FAIL: querySelect('app-element::shadow ui-button::shadow h2') -->
    <h2>app-element > ui-button > h2</h2>
  </template>
</polymer-element>

<polymer-element name="app-element" noscript>
  <template>
    <!-- FAIL: querySelect('app-element::shadow').querySelect('h2') -->
    <!-- FAIL: querySelect('app-element::shadow h2') -->
    <!-- FAIL: querySelect('app-element').shadowRoot.querySelect('h2') -->
    <h2>app-element > h2</h2>
    <content></content>
    <ui-button></ui-button>
  </template>
</polymer-element>
Run Code Online (Sandbox Code Playgroud)

在像"OK:querySelect()"这样的评论中,我展示了我试图从任何阴影DOM外部运行的选择器.

我已经阅读下面的文章:http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201/?redirect_from_locale=ru和基于事实,即它是在文章中说,查询关键词,比如:document.querySelector('app-element::shadow h2');在JS应该按预期工作.然而在Dart中它不起作用.

我错了什么?

小智 18

伪选择器::shadow和组合/deep/器在Firefox上不起作用.

使用 .shadowRoot

var shadowroot = app-element.shadowRoot;
shadowroot.querySelector('h2');
Run Code Online (Sandbox Code Playgroud)

  • 并在 Chrome 63 中被删除。 (4认同)

Gün*_*uer 12

Update2(来自评论)

如果使用自定义main,请确保在尝试与Polymer元素交互之前正确初始化Polymer(有关详细信息,请参阅如何在聚合物应用程序中实现主函数).

我通常建议避免使用自定义main并创建一个app-element(或者你喜欢的任何名称)并将初始化代码放入attached(确保调用super.attached();)或in ready()(不需要超级调用).

原版的

在这种情况下,它似乎不是影子DOM而是孩子.

这应该工作:

querySelector('h2');
Run Code Online (Sandbox Code Playgroud)

它只在shadow DOM中,当它在你的元素中时,而<template>...</template>不是当你将它包装在自定义元素的标记中时.

<polymer-element name="some-element">
  <template>
    <!-- this becomes the shadow DOM -->
    <content>
     <!-- 
       what gets captureD by the content element becomes a child or some-element
       -->
     </content>
  </template>
</polymer-element>
Run Code Online (Sandbox Code Playgroud)
<body>
  <some-element>
    <!-- these elements here are captured by the 
         content tag and become children of some-element -->
    <div>some text</div>
  </some-element>
</body>
Run Code Online (Sandbox Code Playgroud)

更新

如果你想搜索

在当前元素的shadow DOM内

shadowRoot.querySelect('h2');
Run Code Online (Sandbox Code Playgroud)

在阴影DOM内的元素的阴影DOM内

shadowRoot.querySelector('* /deep/ h2');
shadowRoot.querySelector('ui-button::shadow h2');
Run Code Online (Sandbox Code Playgroud)

从当前元素之外

import 'dart:html' as dom;
...
dom.querySelector('* /deep/ h2');
// or (only in the shadow DOM of <app-element>)
dom.querySelector('app-element::shadow h2');
dom.querySelector('app-element::shadow ui-button::shadow h2');
// or (arbitrary depth)
dom.querySelector('app-element /deep/ h2');
Run Code Online (Sandbox Code Playgroud)

  • `::shadow` 和 `/deep/` 在 Chrome 63 中被移除。 (3认同)

nat*_*olt 11

对于想要易于使用的解决方案的人们

function $$$(selector, rootNode=document.body) {
    const arr = []
    
    const traverser = node => {
        // 1. decline all nodes that are not elements
        if(node.nodeType !== Node.ELEMENT_NODE) {
            return
        }
        
        // 2. add the node to the array, if it matches the selector
        if(node.matches(selector)) {
            arr.push(node)
        }
        
        // 3. loop through the children
        const children = node.children
        if (children.length) {
            for(const child of children) {
                traverser(child)
            }
        }
        
        // 4. check for shadow DOM, and loop through it's children
        const shadowRoot = node.shadowRoot
        if (shadowRoot) {
            const shadowChildren = shadowRoot.children
            for(const shadowChild of shadowChildren) {
                traverser(shadowChild)
            }
        }
    }
    
    traverser(rootNode)
    
    return arr
}
Run Code Online (Sandbox Code Playgroud)

像这样使用它:

var nodes = $$$('#some .selector')

// use from a custom rootNode
var buttonsWithinFirstNode = $$$('button', nodes[0])
Run Code Online (Sandbox Code Playgroud)

它会遍历 rootNode 内的所有元素,因此速度不会很快,但很容易使用。