如何获取嵌套Shadow Root中的活跃元素?document.activeElement失效问题
获取嵌套Shadow Root内部的活跃元素
当页面使用嵌套Shadow DOM时,document.activeElement只能返回最外层的Shadow Root宿主元素,无法直接获取内部实际获得焦点的元素。以下是两种无需为每层Shadow Root添加事件监听器的解决方案:
方法1:利用focus事件的composedPath()属性
当Shadow Root的mode为open时,focus事件会穿透Shadow DOM传播到外部,通过事件对象的composedPath()方法可以获取事件传播的完整路径,路径的第一个元素就是实际获得焦点的内部元素。
修改你的示例代码如下:
window.addEventListener('focus', e => { if (e.target instanceof Window) return; // 取composedPath的第一个元素作为实际活跃元素 const actualActiveElement = e.composedPath()[0]; console.log({ target: e.target, activeElement: document.activeElement, actualActiveElement }); }, true);
对应的HTML结构:
<input placeholder="level 1" /> <div id="div2"> <template shadowrootmode="open"> <input placeholder="level 2" /> <div id="div3"> <template shadowrootmode="open"> <input placeholder="level 3" /> <div id="div4"> <template shadowrootmode="open"> <input placeholder="level 4" /> </template> </div> </template> </div> </template> </div>
方法2:递归遍历Shadow Root获取深层活跃元素
编写一个递归函数,从document.activeElement开始,逐层检查元素的shadowRoot,如果该Shadow Root内部有活跃元素,则继续深入,直到找到最内层的活跃元素:
function getDeepActiveElement(element = document.activeElement) { // 如果当前元素有shadowRoot,且内部存在活跃元素 if (element.shadowRoot && element.shadowRoot.activeElement !== element) { return getDeepActiveElement(element.shadowRoot.activeElement); } return element; } // 使用示例:在focus事件中调用 window.addEventListener('focus', e => { if (e.target instanceof Window) return; const deepActiveElement = getDeepActiveElement(); console.log({ activeElement: document.activeElement, deepActiveElement }); }, true);
关于事件监听器的疑问
不需要为每层Shadow Root单独添加事件监听器。只要Shadow Root的mode设置为open,外部代码就可以访问其内部的activeElement,或者通过事件的composedPath()获取完整路径。如果是closed模式的Shadow Root,外部无法访问其内部元素,这种情况下确实无法获取内部活跃元素。
内容的提问来源于stack exchange,提问作者Salmin Skenderovic
相关产品推荐
相关产品推荐

