ecmascript-6 - 有没有办法防止来自 light dom 中的开槽元素的事件通过 shadow dom 传播?
问题描述
问题
我有一个来自第三方库的复杂元素 P,它监听用户交互触发的事件。我想编写一个在其 shadow dom 中包含 P 的 Web 组件,并使用插槽机制,我希望将任何元素 C 元素放入 W 的 light dom 中,以显示在 P 中的某个位置。
我的问题如下:对于交互式元素 C,我希望事件直接传播到 light dom,而不触发 P 中的任何最终事件侦听器。
我试过的
我没有直接在 Pherachy 中添加插槽,而是尝试在我创建的另一个元素中添加插槽,在 Pherachy 中添加此元素并在此元素中冒泡时停止事件传播。在封装方面,这个元素不是来自 light dom 的 sloted 元素的父元素,但这样做仍然会阻止事件到达 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 片段。
<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
解决方案
一种解决方案是在事件传输到 Shadow DOM 之前捕获addEventListener()
事件,方法是将第三个参数设置为to 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 )
推荐阅读
- python - 通过 aiohttp url 传递 unicode
- flutter - 如何在 Flutter 中显示流中的 Snackbar?
- c - 如何使用结构成员打印星期几?
- spring-cloud-feign - 防止 Feign 在 URL 中添加斜杠
- android - 什么导致 Android Studio 错误 EGL_BAD_ATTRIBUTE?
- php - PHP MYSQL 显示表,带有可单击的操作行以打开特定文件
- mysql - 导入大型数据库时的问题静态分析
- javascript - HTML 5 Canvas - 围绕自己的原点旋转多个对象
- apache - htaccess 将所有未找到的 404 重定向到特定 URL
- c# - 在将 Asp.Net WebApi 5.2.2 更新到 5.2.7 后捕获所有不起作用的路由