我创建了一个 Web 组件,并希望访问元素 来自 组件。
我正在使用 .attachMode({mode:'closed'}),因此父级无权访问。
<template id='hello-world-template'>
<span id='inside'>Unchanged,</span> <span id='outside'>Unchanged</span>
<script>
document.querySelector('#inside').innerHTML = 'Changed';
// Ideal, but does not work - no such element
</script>
</template>
<hello-world></hello-world>
<script>
customElements.define('hello-world',
class extends HTMLElement {
constructor() {
super();
var template = document.getElementById('hello-world-template')
var clone = template.content.cloneNode(true)
const shadowRoot = this.attachShadow({mode: 'closed'}).appendChild(clone);
}
connectedCallback() {
this.shadowRoot.querySelector('#outside').innerHTML = 'Changed';
// Not ideal, and also does not work - this.shadowRoot has no querySelector
}
});
</script>
一些尝试:
即使这样可行,它也会破坏使用 {mode:'closed'} 的意义,但无论如何它都不起作用。
我有一个有效的黑客,但无法想象我必须使用它。
封装的全部意义在于事物可以是自包含的,但是如果 JS 不能作用于其容器中的其他项目,那对我们有什么好处呢?
如果这是解决方案,希望有一个提示来解释组件实现方式的逻辑。
不过,这是 hack:包含一个运行 JS onload 的图像。
<template id='hello-world-template'>
<span id='inside'>Unchanged,</span> <span id='outside'>Unchanged</span>
<script>
function runner(img){
let doc = img.parentNode;
doc.querySelector('#inside').innerHTML = 'Changed';
}
</script>
<img src='data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=' onload="runner(this)">
</template>
<hello-world></hello-world>
关于类似问题( 25048359 、 16633057 、 55101967 等)的注意事项 - 当模式关闭时,这些答案将不起作用,这是我需要的。
最佳答案
看起来您在元素引用和 this
中都有错误范围(在 <script>
中)
const shadowRoot = this.attachShadow({mode: 'closed'}).appendChild(clone);
appendChild
是你的克星。它返回插入的元素... 不是 一个影子根,但一个
#document-fragment
(克隆模板)固定为:
const shadowRoot = this.attachShadow({mode: 'closed'});
shadowRoot.appendChild(clone);
然后:
mode:closed
将不是 分配 this.shadowRoot
..你可以不是 重复使用,因为它仍然是只读属性
固定为:
this.Root = this.attachShadow({mode: 'closed'});
this.Root.appendChild(clone);
您现在可以执行以下操作:
connectedCallback() {
this.Root.querySelector('#outside').innerHTML = 'Changed';
}
我不明白你为什么认为这不理想
this.Root
可通过所有/任何方法访问 里面 组件所有 DOM 方法的一个很好的资源是:https://javascript.info/modifying-document
<script>
在 <template>
内(这个范围)<template id='hello-world-template'>
<span id='inside'>Unchanged</span>
<script>
document.querySelector('#inside').innerHTML = 'Changed';
// Ideal, but does not work - no such element
</script>
</template>
您将模板注入(inject)到组件中
document
可以不是 访问元素 里面 任何组件 shadowDOMshadowDOM 是否为
mode:closed
无关紧要或 mode:open
<script>
范围 将是 window
(因为它没有被分配一个范围)(我认为您不能为 SCRIPT 设置 this 范围)
获取
<script>
内的组件范围你必须有创意..并使用您的
img onload=
“黑客”与
onload
在 <style>
element 让它少了一点黑客攻击(恕我直言)<template id='hello-world-template'>
<span id='inside'>Inside Unchanged,</span>
<script>
function templFunc() {
// this scope is the shadowRoot, not the component!
this.querySelector('#inside').innerHTML = 'Changed';
}
</script>
<style onload="templFunc.apply(this.getRootNode())">
#inside{
color:green;
}
</style>
</template>
一个主要问题:只会对第一次使用的
<hello-world>
执行元素!! 这不是我头顶上写的,
(正在进行的工作)JSFiddle 游乐场(还显示了引用组件 方法 ),位于:
https://jsfiddle.net/CustomElementsExamples/zpamx728/
更新#1
Chromium (Edge/Chrome) 和 Opera 都很好,FireFox
v72.0.2
行为不端:onload
在 <STYLE>
元素只会为 触发第一个元素 我使用
<img>
更改了 JSFiddle 以使用您的第一个 hack , 它为每个元素触发 templFunc()
在 shadowDOM 中加载/作用域,因此可以从组件方法调用(参见 JSFiddle)但是.. 仅在 FireFox 中 未定义/不可用第一个元素
现在我认为这是一个 FireFox 错误...将进一步调查...(大胆去哪里...)
!!!更新 #2 !!!
哎呀!用它玩了一些。
从克隆和导入的 SCRIPT 中找出所有变量和函数
被吊到全局
window
范围 所以上面的代码有效,但有一个主要的副作用......
这也是FireFox提示的原因。回复 声明
let
变量
关于javascript - 从 Shadow DOM 中访问元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60097743/