我一直在尝试为特定 Web 组件的 keydown 事件实现一个事件侦听器。事件监听器应该放置在 Web 组件中,这样它也可以在其他项目中使用。我实现了一个 onclick 侦听器,它工作得很好:两种方法(针对文档和针对 Shadow dom)都被调用。但是,这对于 keydown 事件不起作用。
我已经做了一些研究,但是没有找到合适的解决方案,例如这个。根据 this source,keydown 事件应该是“可用的”,因为它具有
composed = true
属性。
下面是我的示例代码。这个问题似乎也出现在 keyup 和 keypress 事件中。我觉得我错过了一个关键点。是否有可能在 Shadow dom 中处理 keydown 事件?
class CustomElement extends HTMLElement {
constructor() {
super();
let template = document.getElementById("custom-template");
this.attachShadow({ mode: "open" });
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
connectedCallback() {
this.shadowRoot.addEventListener("click", (e) => {
alert("click from shadow dom");
});
this.shadowRoot.addEventListener("keydown", (e) => {
e.stopPropagation(); // doesn't seem to change anything
alert("keydown from shadow dom"); // won't run
});
}
}
window.customElements.define("custom-template", CustomElement);
document.addEventListener("click", (e) => {
alert(`click from document; composed: ${e.composed}`);
});
document.addEventListener("keydown", (e) => {
alert(`keydown from document; composed: ${e.composed}`);
});
<custom-template></custom-template>
<template id="custom-template">
<button>Click me</button>
<div>This is a div</div>
</template>
您的元素没有接收键盘事件,因为单击时它没有聚焦。所有元素在单击时都无法接收焦点,因为除以下元素外,它们没有设置 tabindex focus flag 。 [来源:www.w3.org]
如果某个元素未处于焦点状态,则
body
元素会接收键盘事件。
当某个元素获得焦点时,文档接收到的按键事件必须 针对该元素。可能没有重点关注的元素;当没有 元素获得焦点后,文档接收到的关键事件必须是 针对身体元素。 [来源:www.w3.org]
您可以通过添加
tabindex
属性使任何 HTML 元素能够接收焦点,从而接收键盘事件。
最好在 JSFiddle 中使用:https://jsfiddle.net/WebComponents/1muf82nj/
<script>
customElements.define("my-element", class extends HTMLElement {
constructor() {
super().attachShadow({ mode:"open" })
.innerHTML = `<style>
*:focus-within { background:green }
</style>
<button>button</button>
<input>
<div>DIV without tabindex</div>
<div tabindex="0">DIV with tabindex</div>`;
}
connectedCallback() {
const BR = _ => document.createElement("br");
const log = ( e, t=e.target, n=t.nodeName ) =>
this.shadowRoot.append(
BR(),
e.type,
e.type=="keydown" ?" key:"+e.key:"" ," in ",
n=="BODY" ? "e.target=SCRIPT tag!" : t.innerHTML || n
); // append
this.shadowRoot.addEventListener("click", log); // can't do this.shadowRoot.onclick = ...
this.shadowRoot.addEventListener("keydown", log);
document.onkeydown = log;
}
});
</script>
<div><h4>Focus an element, then hit a key</h4></div>
<my-element></my-element>