【问题标题】:Is there a way to prevent events from slotted elements in the light dom from propagating througth the shadow dom?有没有办法防止来自 light dom 中的开槽元素的事件通过 shadow dom 传播?
【发布时间】:2019-12-14 01:14:38
【问题描述】:

问题

我有一个来自第三方库的复杂元素 P,用于侦听由用户交互触发的事件。我想写一个 Web 组件,在它的 shadow dom 中包含 P,并使用 slot 机制,我希望任何放置在 W 的 light dom 中的元素 C 元素都显示在 P 中的某个位置。

我的问题如下:对于交互式元素 C,我希望事件直接传播到 light dom,而不触发 P 中的任何最终事件侦听器。

我尝试了什么

我没有直接在 Pherachy 中添加插槽,而是尝试在我创建的另一个元素中添加插槽,在 Pherachy 中添加此元素并在此元素中冒泡时停止事件传播。在封装方面,这个元素不是来自 light dom 的 sloted element 的父元素,但这样做仍然会阻止事件到达 W。

汇报情况的例子

创建 P (P.js) 的外部库:

export function P(container) {
    const superComplexInnerHierachy = document.createElement("div")

    superComplexInnerHierachy.textContent = "Some P lib's interactive stuff"

    superComplexInnerHierachy.addEventListener(
        "click",
        () => console.log("I'm the third party P lib, I do stuff on click.")
    )

    container.append(d1)

    const thingsIDo = {
      add : (elem) => {
        superComplexInnerHierachy.append(elem)
        superComplexInnerHierachy.append("More P lib's interactive stuff")
      }
    }

    return thingsIDo

}

我正在尝试编写的网络组件 W (W.js):

import {P} from "P.js"

class W extends HTMLElement {
    constructor(){

        this.attachShadow({mode : "open"})

        this.value = "Something else"

        // Create the lib stuff in the shadow root
        this.p = P(this.shadowRoot)

        // Add a slot in P's hierachy to inject an element from the light dom
        const slot = document.createElement("slot")
        this.p.add(slot)
    }
}
customElements.define("w-component", W);

使用 W 的 html sn-p。

<script type="module" src="W.js"></script>

<w-component>
   <div name="an_interactive_element_usupecting_of_P">
      <input type="button" value="Button A">
      <input type="button" value="Button B">
   </div>

</w-component>

<script type="text/javascript">
    document.querySelector("w-component")
        .addEventListener("click", evt => {
            console.log(`${evt.target.value} was clicked`)
        })
</script>

行为

当前代码的行为

点击 A 时

I'm the third party P lib, I do stuff on click.

Button A was clicked

点击P添加的东西时

I'm the third party P lib, I do stuff on click.

Something else was clicked

想要什么

点击 A 时

Button A was clicked

点击P添加的东西时

I'm the third party P lib, I do stuff on click.

Something else was clicked

【问题讨论】:

    标签: ecmascript-6 web-component dom-events shadow-dom


    【解决方案1】:

    解决方案可以是在事件传输到 Shadow DOM 之前捕获事件,方法是将 addEventListener() 的第三个参数设置为 true

    如果您检测到它来自一个开槽元素并且您可以自己处理它,请致电stopPropagation() 以防止其传播。

    document.querySelector("w-component").addEventListener("click", evt => {
        console.log(`${evt.target.value} was clicked`)
        if ( evt.path.findIndex( elem => elem.localName === "slot" ) !== -1 )
            evt.stopPropagation()
    }, true )
    

    【讨论】:

    • 我对这个解决方案并不完全满意。我认为您提出的解决方案也可以防止事件在开槽元素内传播。在我的例子中,这些元素比简单的按钮更复杂,它们可能需要让事件在内部传播。
    • @ThibaultUrien 然后在自定义元素中捕获事件并在需要时重新发送自定义事件
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-31
    • 2017-06-24
    • 1970-01-01
    • 1970-01-01
    • 2021-11-05
    • 1970-01-01
    相关资源
    最近更新 更多