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

kzipqqlq  于 2023-01-28  发布在  其他
关注(0)|答案(5)|浏览(118)

如何在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>
    • 索引. 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>
    • 模板. 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>

在"OK:querySelect()"我显示了我试图从任何阴影DOM外部运行的选择器。
我已经读过下面的文章:http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201/?redirect_from_locale=ru,并基于文章中提到的事实,查询如下:JS中的document.querySelector('app-element::shadow h2');应该可以正常工作。但是在Dart中它不工作。
我哪里错了?

xfb7svmp

xfb7svmp1#

伪选择器::shadow和组合器/deep/在firefox上不起作用。
使用.shadowRoot

var shadowroot = app-element.shadowRoot;
shadowroot.querySelector('h2');
gpfsuwkq

gpfsuwkq2#

    • 更新2(根据评论)**

如果使用自定义main,请确保在尝试与Polymer元素交互之前正确初始化Polymer(有关更多详细信息,请参见how to implement a main function in polymer apps)。
我通常建议不要使用自定义main,而是创建一个app-element(或者您喜欢的任何名称),并将初始化代码放入attached(确保调用super.attached();)或ready()(不需要超级调用)。

    • 原件**

在本例中,它似乎不在影子DOM中,而是一个子对象。
这应该行得通:

querySelector('h2');

只有当它在元素<template>...</template>中时,它才在shadow DOM中,而不是当您将它 Package 在自定义元素的标记中时。
x一个一个一个一个x一个一个二个x

    • 更新**

如果你想搜索
在当前元素的阴影DOM中

shadowRoot.querySelect('h2');

在影子DOM内的元素的影子DOM内

shadowRoot.querySelector('* /deep/ h2');
shadowRoot.querySelector('ui-button::shadow h2');

从当前元素外部

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');
nkcskrwz

nkcskrwz3#

适用于需要易于使用的解决方案的用户

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
}

像这样使用它:

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

// use from a custom rootNode
var buttonsWithinFirstNode = $$$('button', nodes[0])

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

4c8rllxm

4c8rllxm4#

使用reduce方法的Vanilla专用辅助函数

function queryShadow([firstShadowSelector, ...restOfTheShadowSelectors], itemSelector) {
    const reduceFunction = (currShadow, nextShadowSelector) => currShadow.shadowRoot.querySelector(nextShadowSelector);    
    const firstShadow = document.querySelector(firstShadowSelector);
    const lastShadow = restOfTheShadowSelectors.reduce(reduceFunction,firstShadow);
    return lastShadow && lastShadow.querySelector(itemSelector);
}

像这样使用它

const shadowSelectorsArr = ['vt-virustotal-app','file-view', '#report', 'vt-ui-file-card', 'vt-ui-generic-card'];
const foundDomElem = queryShadow(shadowSelectorsArr, '.file-id');
console.log(foundDomElem && foundDomElem.innerText);
blpfk2vs

blpfk2vs5#

这是一个老问题,但我很惊讶没有通用的解决方案(不仅仅是在 dart )。让我们解决它的所有情况

// query elements even deeply within shadow doms. e.g.:
// ts-app::shadow paper-textarea::shadow paper-input-container
function querySelectorDeep(selector, root = document) {
  let currentRoot = root;
  let partials = selector.split('::shadow');
  let elems = currentRoot.querySelectorAll(partials[0]);
  for (let i = 1; i < partials.length; i++) {
    let partial = partials[i];
    let elemsInside = [];
    for (let j = 0; j < elems.length; j++) {
      let shadow = elems[j].shadowRoot;
      if (shadow) {
        const matchesInShadow = shadow.querySelectorAll(partial);
        elemsInside = elemsInside.concat([... matchesInShadow]);
      }
    }
    elems = elemsInside;
  }
  return elems;
}

试用示例:
1.转到Google's text-to-speech demo
1.打开控制台并输入:

let sel = `ts-app::shadow 
           paper-textarea::shadow 
           paper-input-container 
           iron-autogrow-textarea::shadow
           textarea`;
textarea = querySelectorDeep(sel)?.[0];
textarea.value = 'If you see this, selector worked.';
  • 注意:这个问题也可以递归求解,但我只是使用迭代。*

相关问题