6

如何删除window我在下面绑定的点击侦听器constructor?我需要它来监听window,并且我需要访问其中的按钮实例。

class MyEl extends HTMLButtonElement {
  constructor() {
    super();
    this.clickCount = 0;
    window.addEventListener('click', this.clickHandler.bind(this));
  }
  
  clickHandler(e) {
    if (e.target === this) {
      this.textContent = `clicked ${++this.clickCount} times`;
      window.removeEventListener('click', this.clickHandler);
    }
  }
  
  disconnectedCallback() {
      window.removeEventListener('click', this.clickHandler);
  }
}

customElements.define('my-el', MyEl, { extends: 'button' });
<button is="my-el" type="button">Click me</button>

4

3 回答 3

11

您当前的实现不可能 - 每次调用都会创建一个新的单独函数,并且如果传递的函数与传递给的函数相同 ( ) .bind,您只能调用removeEventListener删除侦听器(就像数组或集合一样) :===addEventListener.includes.has

const fn = () => 'foo';
console.log(fn.bind(window) === fn.bind(window));

作为一种解决方法,您可以将绑定函数分配给实例的属性:

class MyEl extends HTMLButtonElement {
  constructor() {
    super();
    this.clickCount = 0;
    this.boundListener = this.clickHandler.bind(this);
    window.addEventListener('click', this.boundListener);
  }
  
  clickHandler(e) {
    this.textContent = `clicked ${++this.clickCount} times`;
    window.removeEventListener('click', this.boundListener);
  }
}

customElements.define('my-el', MyEl, { extends: 'button' });
<button is="my-el" type="button">Click me</button>

于 2019-02-28T08:12:37.840 回答
2

像这样为您的 clickHandler 创建一个包装函数。

class MyEl extends HTMLButtonElement {
  constructor() {
    super();
    this.clickCount = 0;
    this.wrapper = e => this.clickHandler.apply(this, e);
    window.addEventListener('click', this.wrapper);
  }
  
  clickHandler(e) {
    this.textContent = `clicked ${++this.clickCount} times`;
    
    window.removeEventListener('click', this.wrapper);
  }
}

customElements.define('my-el', MyEl, { extends: 'button' });
<button is="my-el" type="button">Click me</button>

于 2019-02-28T08:13:56.307 回答
1

另一种模式是将您的侦听器保留构造函数中。

要删除事件侦听器(无论何种模式),您可以在创建事件侦听器时添加“删除”功能。

由于 remove函数是在作用域内调用的listen,所以它使用相同的namefunc

伪代码:

  listen(name , func){
    window.addEventListener(name, func);
    return () => window.removeEventListener( name , func );
  }

  let remove = listen( 'click' , () => alert('BOO!') );

  //cleanup:
  remove();

运行下面的代码片段以查看它与多个按钮一起使用

冒泡的事件和 shadowDOM

一旦您对事件进行更多操作,可以为您节省一个小时...

请注意,如果您希望WebComponents(即带有 shadowDOM 的CustomElements)在其 shadowDOM 边界之外冒泡则需要带有该属性的 CustomEventscomposed:true

    new CustomEvent("check", {
      bubbles: true,
      //cancelable: false,
      composed: true       // required to break out of shadowDOM
    });

删除添加的事件侦听器

注意:这个例子不能在 Safari 上运行,因为 Apple 拒绝实现扩展元素:extends HTMLButtonElement

class MyEl extends HTMLButtonElement {
  constructor() {
    let ME = super();// super() retuns this scope; ME makes code easier to read
    let count = 0;// you do not have to stick everything on the Element
    ME.mute = ME.listen('click' , event => {
      //this function is in constructor scope, so has access to ALL its contents
      if(event.target === ME) //because ALL click events will fire!
        ME.textContent = `clicked ${ME.id} ${++count} times`;
      //if you only want to allow N clicks per button you call ME.mute() here
    });
  }

  listen(name , func){
    window.addEventListener( name , func );
    console.log('added' , name , this.id );
    return () => { // return a Function!
      console.log( 'removeEventListener' , name , 'from' , this.id);
      this.style.opacity=.5;
      window.removeEventListener( name , func );
    }
  }
  eol(){ // End of Life
    this.parentNode.removeChild(this);
  }
  disconnectedCallback() {
      console.log('disconnectedCallback');
      this.mute();
  }
}

customElements.define('my-el', MyEl, { extends: 'button' });
button{
  width:12em;
}
<button id="One" is="my-el" type="button">Click me</button>
<button onclick="One.mute()">Mute</button> 
<button onclick="One.eol()">Delete</button> 
<br>
<button id="Two" is="my-el" type="button">Click me too</button>
<button onclick="Two.disconnectedCallback()">Mute</button> 
<button onclick="Two.eol()">Delete</button> 

笔记:

  • count不可用,this.count但可用于定义在构造函数范围内的所有函数。所以它是(有点)私有的,只有点击功能可以更新它。

  • onclick=Two.disconnectedCallback()就像示例该函数不会删除元素。


另见:https ://pm.dartus.fr/blog/a-complete-guide-on-shadow-dom-and-event-propagation/

于 2019-03-01T13:41:28.660 回答