如何向shadow dom添加keydown监听器

问题描述 投票:0回答:1

我一直在尝试为特定 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>

javascript html events web-component shadow-dom
1个回答
2
投票

来源:如何使按键事件的目标等于“选定”元素?

您的元素没有接收键盘事件,因为单击时它没有聚焦。所有元素在单击时都无法接收焦点,因为除以下元素外,它们没有设置 tabindex focus flag[来源:www.w3.org]

  • <a>
    具有 href 属性的元素
  • <link>
    具有 href 属性的元素
  • <button>
    元素
  • <input>
    type 属性不处于隐藏状态的元素
  • <select>
    元素
  • <textarea>
    元素
  • 编辑主机
  • 浏览上下文容器

如果某个元素未处于焦点状态,则

body
元素会接收键盘事件。

当某个元素获得焦点时,文档接收到的按键事件必须 针对该元素。可能没有重点关注的元素;当没有 元素获得焦点后,文档接收到的关键事件必须是 针对身体元素[来源:www.w3.org]

您可以通过添加

tabindex
属性使任何 HTML 元素能够接收焦点,从而接收键盘事件。

Web 组件 ShadowDOM 示例:

最好在 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>

© www.soinside.com 2019 - 2024. All rights reserved.