如何在 Dart 中从外部查询 shadow DOM 内的元素?
How to query elements within shadow DOM from outside in Dart?
如何 select 影子 DOM 中的节点?考虑以下示例:
"unshadowed"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>
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>
在 "OK: querySelect()" 之类的评论中,我展示了 select 或我尝试从外部 运行 任何阴影 DOM。
我已经阅读了以下文章:http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201/?redirect_from_locale=ru 并且根据文章中所说的事实,查询如:document.querySelector('app-element::shadow h2');
在 JS 中应该按预期工作。但是在 Dart 中它不起作用。
我做错了什么?
Update2(来自评论)
如果您使用自定义 main,请确保在尝试与 Polymer 元素交互之前正确初始化 Polymer(有关详细信息,请参阅 how to implement a main function in polymer apps)。
我通常建议避免自定义 main 并创建一个 app-element
(或您喜欢的任何名称)并将您的初始化代码放入 attached
(确保调用 super.attached();
)或在 ready()
中(不需要 super 调用)。
原创
在这种情况下,它似乎不在阴影 DOM 中,而是 child。
这应该有效:
querySelector('h2');
只有当它在您的元素中时才会出现在阴影中 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>
<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>
更新
如果要搜索
在当前元素的阴影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');
伪选择器 ::shadow
和组合器 /deep/
在 firefox 上不起作用。
使用.shadowRoot
var shadowroot = app-element.shadowRoot;
shadowroot.querySelector('h2');
使用 reduce 方法的纯辅助函数
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);
对于想要简单易用的解决方案的人
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])
它会遍历根节点内的所有元素,所以速度不会很快,但很容易使用。
如何 select 影子 DOM 中的节点?考虑以下示例:
"unshadowed"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>
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>
在 "OK: querySelect()" 之类的评论中,我展示了 select 或我尝试从外部 运行 任何阴影 DOM。
我已经阅读了以下文章:http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201/?redirect_from_locale=ru 并且根据文章中所说的事实,查询如:document.querySelector('app-element::shadow h2');
在 JS 中应该按预期工作。但是在 Dart 中它不起作用。
我做错了什么?
Update2(来自评论)
如果您使用自定义 main,请确保在尝试与 Polymer 元素交互之前正确初始化 Polymer(有关详细信息,请参阅 how to implement a main function in polymer apps)。
我通常建议避免自定义 main 并创建一个 app-element
(或您喜欢的任何名称)并将您的初始化代码放入 attached
(确保调用 super.attached();
)或在 ready()
中(不需要 super 调用)。
原创
在这种情况下,它似乎不在阴影 DOM 中,而是 child。
这应该有效:
querySelector('h2');
只有当它在您的元素中时才会出现在阴影中 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>
<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>
更新
如果要搜索
在当前元素的阴影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');
伪选择器 ::shadow
和组合器 /deep/
在 firefox 上不起作用。
使用.shadowRoot
var shadowroot = app-element.shadowRoot;
shadowroot.querySelector('h2');
使用 reduce 方法的纯辅助函数
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);
对于想要简单易用的解决方案的人
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])
它会遍历根节点内的所有元素,所以速度不会很快,但很容易使用。