簡體   English   中英

如何在 Dart 中從外部查詢 shadow DOM 中的元素?

[英]How to query elements within shadow DOM from outside in Dart?

我如何在 shadow DOM 中設置 select 個節點? 考慮以下示例:

“無陰影”DOM 的結構

<app-element>
  #shadow-root
    <h2></h2>
    <content>
      #outside shadow
      <h2></h2>
    </content>
    <ui-button>
      #shadow-root
        <h2></h2>
  </ui-button>
</app-element>

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>

模板.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並根據文章中所說的事實,查詢如下: document.querySelector('app-element::shadow h2'); 在 JS 中應該按預期工作。 但是在 Dart 中它不起作用。

我做錯了什么?

偽選擇器::shadow和組合器/deep/在 Firefox 上不起作用。

使用.shadowRoot

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

Update2(來自評論)

如果您使用自定義 main,請確保在您嘗試與您的 Polymer 元素交互之前正確初始化 Polymer(有關更多詳細信息,請參閱如何在 Polymer 應用程序中實現 main 函數)。

我通常建議避免使用自定義 main 並創建一個app-element (或您喜歡的任何名稱)並將您的初始化代碼放入attached (確保調用super.attached(); )或ready() (不需要超級通話)。

原來的

在這種情況下,它似乎不在 shadow DOM 中,而是在 child 中。

這應該有效:

querySelector('h2');

當它在你的元素<template>...</template>時,它只在 shadow DOM 中,而不是當你將它包裝在你的自定義元素的標簽中時。

<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>
<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>

更新

如果你想搜索

當前元素的 shadow DOM 內部

shadowRoot.querySelect('h2');

在 shadow DOM 內部元素的 shadow 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');

對於想要易於使用的解決方案的人

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中的所有元素,所以速度不會很快,但很容易使用。

使用reduce方法的Vanilla only helper函數

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

這是一個老問題,但令我驚訝的是沒有通用的解決方案(不僅僅是在 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. Go 轉谷歌文字轉語音演示
  2. 打開控制台並輸入:
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.';

注意:這也可以遞歸解決,但我只是用迭代來解決。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM