如何在Shadow Root父元素中获取keyup事件的contenteditable目标元素?
如何在Shadow Root事件冒泡中获取实际触发的contenteditable元素?
我在Chrome扩展的content script中创建了一个Shadow Root,结构如下:
<div id="container" onkeyup="catchEventsFun"> <div id="parent-1"> <div contenteditable id="child-1"></div> </div> <div id="parent-2"> <div contenteditable id="child-2"></div> </div> <div id="parent-3"> <div contenteditable id="child-3"></div> </div> </div>
问题:当child-2触发keyup事件时,catchEventsFun中捕获的event.target是Shadow Root元素,而非实际触发的子元素。
已尝试的方法:
- 使用
composedPath或path:path为null,composedPath返回空数组,event.composed为true,但无效 - 使用
event.currentTarget:返回null,无效
解决方案
方法1:移除内联事件,在Shadow DOM内部通过JS绑定事件监听器
内联事件处理器(onkeyup="catchEventsFun")运行在主文档的全局上下文,无法正确访问Shadow DOM内的事件目标。改为在Shadow Root内部直接绑定事件:
// 创建Shadow Root的content script代码 const hostElement = document.querySelector('#your-host-element'); // 替换为你的宿主元素 const shadowRoot = hostElement.attachShadow({ mode: 'open' }); // 插入Shadow DOM内容(包含container) shadowRoot.innerHTML = ` <div id="container"> <div id="parent-1"> <div contenteditable id="child-1"></div> </div> <div id="parent-2"> <div contenteditable id="child-2"></div> </div> <div id="parent-3"> <div contenteditable id="child-3"></div> </div> </div> `; // 获取container并绑定事件 const container = shadowRoot.getElementById('container'); container.addEventListener('keyup', catchEventsFun); function catchEventsFun(event) { // 此时event.target就是实际触发事件的child元素 console.log('触发元素:', event.target); }
方法2:在Shadow DOM内部定义事件处理函数(保留内联事件的场景)
如果必须使用内联事件,需要将catchEventsFun定义在Shadow DOM的上下文内,让它能访问内部元素:
// 创建Shadow Root的content script代码 const hostElement = document.querySelector('#your-host-element'); const shadowRoot = hostElement.attachShadow({ mode: 'open' }); // 插入内容和脚本 shadowRoot.innerHTML = ` <div id="container" onkeyup="catchEventsFun(event)"> <div id="parent-1"> <div contenteditable id="child-1"></div> </div> <div id="parent-2"> <div contenteditable id="child-2"></div> </div> <div id="parent-3"> <div contenteditable id="child-3"></div> </div> </div> <script> function catchEventsFun(event) { console.log('触发元素:', event.target); } </script> `;
原因说明
内联事件的执行上下文是主文档全局,而Shadow DOM的内部元素对全局上下文是隔离的,导致事件的composedPath无法正确传递内部元素信息。将事件绑定或处理函数放在Shadow DOM内部上下文,就能直接获取到实际触发事件的元素。
内容的提问来源于stack exchange,提问作者Lerner Zhang
相关产品推荐
相关产品推荐

