Shadow DOM 内的元素无法绑定到 Shadow DOM 外部的事件监听器。

5
我在我的网站上安装了一个Angular网络组件。它使用Shadow DOM,因此非常快(在我的情况下必须如此)。
在我的网站上,我还有一个在键盘按h键时打开弹出窗口以显示一些有用信息的快捷方式。这个h键绑定必须保持不变。在此处可以看到如何实现示例代码:https://jsfiddle.net/js1edv37/ 这是一个简单的事件侦听器,监听document:
$(document).on("keyup", function(e) {

}

然而,当我的网络组件有焦点的textareainput元素时,这也会被触发。这是因为它使用了Shadow DOM,外部的脚本无法访问。
您可以通过在inputtextarea元素内外按键盘上的h键来测试它。
是否有一种方法让我的来自Shadow DOM网络组件外部的脚本,仍然监听keyup事件,但使其监听页面上的所有元素?甚至是在影子DOM中的元素。
2个回答

5
在Web组件中,通过在shadowRoot属性上调用querySelector()来获取输入元素:
let textareainshadow = div.shadowRoot.querySelector( 'textarea' )

然后监听 keyup 事件,使用 stopImmediatePropagation() 方法停止事件传播。

textareainshadow.addEventListener( 'keyup' , ev => {
    console.log( 'caught', ev.type )
    ev.stopImmediatePropagation()
}) 

https://jsfiddle.net/7mkrxh25/1/


我无法访问生成影子 DOM 的代码。这一切都是通过 Angular 完成的,所以这样做行不通。我正在设置一个 StackBlitz 来演示我的问题。 - MortenMoulder
如果您可以获取到 Angular Web 组件的引用 (ref),那么您就可以通过 ref.shadowRoot 访问其 Shadow DOM。或者在 Angular 代码内部使用 this.shadowRoot - Supersharp
很遗憾,这不起作用,因为我无法访问该引用。我不知道如何做。您可以在工作示例中查看:https://stackblitz.com/edit/angular-webcomponent-polyfill-w2xff4?file=src%2Findex.html - index.html 包含 Web 组件(Shadow DOM)和文本区域。您会如何解决它? - MortenMoulder
啊,我明白了。现在运行得很完美。非常感谢。 - MortenMoulder

2
如果您保存了对影子根的引用,您就可以始终将其子元素视为搜索结果。最初的回答。

$(document).on("keyup", function(e) {
    let focusedInputs = $("input:focus, textarea:focus").length + $(shadow).children("input:focus, textarea:focus").length;

    if (focusedInputs > 0) {
        return true;
    }

    if (e.keyCode === 72) {
        trigger();
    }
});

function trigger() {
    alert("If this was triggered, everything is perfectly fine");
}

let div = document.querySelector("div");
let shadow = div.createShadowRoot();
shadow.innerHTML = "<textarea>This shouldn't fail</textarea>";
textarea {
    width: 500px;
    height: 100px;
}

input {
    width: 250px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<textarea>Some stuff here</textarea>
<br />
<input type="text" value="Some more text here" />

<br />
<br />

<h1>Shadow DOM element WON'T fail now :)</h1>

<div></div>

Fiddle


我没有引用阴影根。我的 Shadow DOM 包含在 Angular Web 组件中。不幸的是,这并不起作用。所有这一切都是因为封装。也许我表达问题的方式不对。 - MortenMoulder
@MortenMoulder 不,这只是我太迟钝了,没有仔细阅读你的问题,你确实说过“这是因为它使用了Shadow DOM,外部脚本无法访问。” - George
没错,我很想说:“如果我的网页组件在这个页面上,只需忽略keyup/return true”。然而,这并不起作用,因为我的网页组件占用了大约75%的页面空间。我猜我真的没什么可做的:( - MortenMoulder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接