【问题标题】:Event listener outside of Shadow DOM won't bind to elements inside of Shadow DOMShadow DOM 外部的事件侦听器不会绑定到 Shadow DOM 内部的元素
【发布时间】:2019-09-06 07:52:33
【问题描述】:

我的网站上安装了一个 Angular Web 组件。它使用 Shadow DOM,因此速度非常快(在我的情况下必须如此)。

在我的网站上,我还有一个关于 h 的快捷方式,它会打开一个弹出窗口,其中显示一些有用的信息。这个 h 键绑定必须保持原样。它是如何实现的示例代码可以在这里看到:https://jsfiddle.net/js1edv37/

这是一个简单的事件监听器,监听document:

$(document).on("keyup", function(e) {

}

但是,当我的 Web 组件聚焦 textarea 或 input 元素时,这也会触发。发生这种情况是因为它使用了 Shadow DOM,而外部脚本无法访问。

您可以通过在input 和textarea 元素内外按键盘上的h 来测试它。

有没有办法让 Shadow DOM Web 组件外部的脚本仍然监听 keyup 事件,但让它监听页面上的 所有 元素?甚至是 Shadow DOM 中的那些。

【问题讨论】:

    标签: javascript jquery shadow-dom


    【解决方案1】:

    在 Web 组件中,通过 querySelector() 调用 shadowRoot 属性获取输入元素:

    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 来证明我的问题。
    • 我可以获取到 Angular Web 组件的引用 (ref),您应该可以通过 ref.shadowRoot 访问它的 shadow dom。或者从角码内部:this.shadowRoot.
    • 不幸的是,这不起作用,因为我无法访问参考。我不知道怎么做。您可以在一个工作示例中看到这一点:stackblitz.com/edit/… - index.html 包含 Web 组件(Shadow DOM)以及文本区域。你会怎么解决呢?
    • 啊啊啊我明白了,现在。完美运行。非常感谢。
    【解决方案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 不,只是我很密集,没有彻底阅读您的问题,您确实说过“发生这种情况是因为它使用了 Shadow DOM,而外部脚本无法访问。”
    • 正是哈哈。我想说“如果我的 web 组件在这个页面上,只需忽略 keyup/return true”。但是,这行不通,因为我的 Web 组件占据了大约 75% 的页面。我想我真的无能为力:(
    猜你喜欢
    • 1970-01-01
    • 2016-09-18
    • 2020-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多