javascript web组件-slotchange上的自定义事件

6pp0gazn  于 2022-12-21  发布在  Java
关注(0)|答案(1)|浏览(182)

有人能解释一下这里发生了什么吗?我错过了什么吗?

#handleClick() {
  this.dispatchEvent(new Event('onClicked'));
}
mySlot.addEventListener('slotchange', () => {
   mySlot.addEventListener('click', this.#handleClick); // doesn't work
   mySlot.addEventListener('click', () => this.#handleClick()); // works
});
...
myCustomElement.addEventListener('onClicked', (e) => {
  console.log(e, e.detail);
});
#handleClick() {
  this.dispatchEvent(new Event('onClicked', {bubbles: true, composed: true}));
}
mySlot.addEventListener('slotchange', () => {
   mySlot.addEventListener('click', this.#handleClick); // works
});
...
...
myCustomElement.addEventListener('onClicked', (e) => {
  console.log(e, e.detail);
});

我知道自定义事件不会直接到达"light-DOM",这就是为什么我可以理解为什么我们应该将"composed:真实和气泡:但是为什么mySlot. addEventListener('click ',()=〉this.#handleClick())可以在不需要将事件设置为"可组合"的情况下工作呢?
为了更好地理解这个问题,下面是一个小提琴:https://jsfiddle.net/rv6w3xj1/1/

hmmo2u0o

hmmo2u0o1#

您的问题是范围***
函数
引用获得的this作用域与箭头函数定义不同,
因此this.dispatchEvent是在不同的DOM元素上执行的。
当该元素位于shadowDOM中时,它需要bubbles:true;composed:true来通过shadowRoot进行 * 转义
我将您的代码精简到最低限度,slotslotchange
此***无关

<custom-element><h2>Click SLOT</h2></custom-element>

<script>
  customElements.define('custom-element', class extends HTMLElement {
    constructor() {
      super().attachShadow({ mode: "open" })
             .innerHTML = `<h1>Click H1</h1><slot></slot>`;
      const addClick = (name) => {
        const el = this.shadowRoot.querySelector(name);
        el.addEventListener('click',        this.#handleClick    ); // func REF
        el.addEventListener('click', (e) => this.#handleClick(e) ); // func DEF
      }
      addClick("h1");
      addClick("slot");
    }
    #handleClick(e) {
      console.error(e.type, 'handleClick scope:', this);
      this.dispatchEvent(new CustomEvent('onClicked', {
        bubbles: true, composed: true,
      }));
    }
  });

  document.querySelector('custom-element').addEventListener('onClicked', (e) => {
    console.log("target:", e.target, e.target.getRootNode(), 
                "\ncomposedPath[0]:", e.composedPath()[0]);
  });
</script>

您可以使用 oldskoolthis.handleClick.bind(this)进行修复,
但这比(e) => this.handleClick(e)更容易出错
因为大多数初级开发人员不了解bind的工作原理

相关问题