[英]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;
}
試用示例:
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.