如何将 keyup 事件附加到自定义元素 shadowRoot

How to attach a keyup event to Custom Element shadowRoot

我已经搜索了一段时间;但只能找到 Polymer 答案;
或将 EventListeners 放在 DOM 元素 内部 shadowRoot 中的答案。

我尝试使用原生自定义元素实现的效果:

可以将点击事件附加到 shadowRoot,看来我对 'keyup' 事件做错了。

如果我将 EventListener 放在 window 上,所有元素(当然)都会更新为相同的密钥信息。

window.customElements.define('game-toes', class extends HTMLElement {
  constructor() {
    super().attachShadow({mode:'open'})
           .innerHTML = this.tabIndex;
    this.addEventListener('keyup',evt=>this.shadowRoot.innerHTML = 'key:'+evt.key);        
  }
});
game-toes{
  display:inline-block;
  height:auto;
  width:100px;
  padding:1em;
  border:10px solid green;
}
game-toes:focus { 
  background-color: lightgreen;
}
<game-toes tabindex=1></game-toes>
<game-toes tabindex=2></game-toes>
<game-toes tabindex=3></game-toes>

在您的示例中,tabindex 属性设置为自定义元素 <game-toes>,而不是其影子 DOM。

因此,您应该改为监听自定义元素本身的 keyup 事件:

this.addEventListener('keyup',evt=>this.shadowRoot.innerHTML = 'key:'+evt.key);

window.customElements.define('game-toes', class extends HTMLElement {
  constructor() {
    super();
    let shadowRoot=this.attachShadow({mode: 'open'});
    shadowRoot.innerHTML = this.tabIndex;
    this.addEventListener('keyup',evt=>this.shadowRoot.innerHTML = 'key:'+evt.key);        
  }
});
game-toes{
  display:inline-block;
  height:auto;
  width:100px;
  padding:1em;
  border:10px solid green;
}
game-toes:focus { 
  background-color: lightgreen;
}
<game-toes tabindex=1></game-toes>
<game-toes tabindex=2></game-toes>
<game-toes tabindex=3></game-toes>

或者,如果你想在 Shadow DOM 级别监听 keyup 事件,你应该在 Shadow DOM 内的元素中设置 tabindex 属性.

您可以照原样操作,但需要添加一些额外的代码才能使其正常工作:

function on(el, evt, cb) {
  el.addEventListener(evt, cb);
  return () => {
    el.removeEventListener(evt, cb);
  }
}


window.customElements.define('game-toes', class extends HTMLElement {
  constructor() {
    super()
      .attachShadow({mode: 'open'})
      .innerHTML = this.tabIndex;
  }
  
  connectedCallback() {
    this._offKeyup = on(this, 'keyup', evt => {
      this.shadowRoot.innerHTML = evt.key;
      evt.stopPropagation(); // Prevent the event from leaving this element
    });
  }
  
  disconnectedCallback() {
    this._offKeyup();
  }
});
game-toes{
  display:inline-block;
  height:auto;
  width:100px;
  padding:1em;
  border:10px solid green;
}
game-toes:focus { 
  background-color: lightgreen;
}
<game-toes tabindex=1></game-toes>
<game-toes tabindex=2></game-toes>
<game-toes tabindex=3></game-toes>

  1. 您可能想使用 evt.stopPropagation() 来阻止事件离开组件。
  2. 您要么需要在组件本身上添加 eventListener,要么在 shadowRoot 中创建一个能够获得焦点的元素,然后在组件获得焦点时将焦点设置到内部元素。然后您应该能够在该内部元素上添加 keyup 事件。
  3. 最安全的做法是在 connectedCallback 中添加 eventListener 并在 disconnectedCallback 中释放它们,除非您不打算删除组件。