新的 Popover API 在以声明方式使用时,无法跨阴影边界工作。在创建可重用的 Web 组件时,这是一个限制,这些组件封装了一些逻辑,并且在内部使用
popover
,同时依赖于 light DOM 中的外部触发器。
根据 keithamus 的解释,应该可以通过 JavaScript API 跨越阴影边界连接 popoverTarget
和
popover
。我尝试测试它,但我的示例似乎不起作用:
<test-popup>hello, this is a test</test-popup>
<button popovertarget="testpopup" id="shadow-popover-trigger">this should cross shadow boundaries and trigger a popup</button>
const template = document.createElement("template");
template.innerHTML = `
<div popover id="testpopup">
<slot></slot>
</div>
`;
class TestPopup extends HTMLElement {
constructor() {
super();
this._shadowRoot = this.attachShadow({ mode: "open" });
this._shadowRoot.appendChild(template.content.cloneNode(true));
const trigger = document.querySelector('[popovertarget="testpopup"]');
const popover = this._shadowRoot.querySelector("[popover]");
trigger.popoverTargetElement = popover;
}
}
customElements.define("test-popup", TestPopup);
此实现中是否存在错误,或者 Chrome 118 不支持此功能?还可以在 codepen 上找到示例:
popover
inside ShadowDOM 由
button
outside ShadowDOM 触发 请注意,FireFox 尚不支持 Popover API(2023 年 10 月)
看起来
beforetoggle
事件并没有逃逸shadowDOM;也许这就是为什么我无法让
.togglePopover()
方法发挥作用。解决方法是让 Web 组件添加一个
click
事件监听器(到“外部”
<button>
)并自己执行
display:none/block
。获取该按钮需要在具有多个 ShadowRoot 的 DOM 中进行一些额外的工作
<button id="B1">Toggle Popover</button>
<wc-popover id="P1" button="B1">I am a popover element</wc-popover>
<script>
P1.addEventListener("beforetoggle", _ => console.log("beforetoggle P1"));
customElements.define("wc-popover", class extends HTMLElement {
constructor(open = false) {
super()
.attachShadow({mode: "open"})
.innerHTML = `<slot popover></slot>`;
document
.querySelector("#" + this.getAttribute("button"))
.addEventListener("click", () => {
this
.shadowRoot.querySelector("[popover]")
.style.display = (open = !open) ? "block" : "none";
})
}
});
</script>