Удалить прослушиватель событий, который был добавлен с помощью bind (this) - PullRequest
0 голосов
/ 28 февраля 2019

Как мне удалить прослушиватель кликов, который я привязал к 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>

Ответы [ 3 ]

0 голосов
/ 28 февраля 2019

Создайте функцию-обёртку для вашего 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>
0 голосов
/ 01 марта 2019

Другим шаблоном является сохранение вашего слушателя внутри конструктора.

Чтобы удалить слушателя событий (независимо от того, какой шаблон), вы можете добавить «удалить» функция в момент создания прослушивателя событий.

Поскольку функция удаления вызывается в области действия listen, в ней используются те же name и func tion

псевдокод:

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

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

  //cleanup:
  remove();

Запустите фрагмент кода ниже, чтобы увидеть, как он используется с несколькими кнопками

События всплывают вверх & shadowDOM

, чтобы сэкономить вам час, как только вы сделаете больше с событиями ...

Обратите внимание, что WebComponents (то есть CustomElements с shadowDOM) нужны CustomEvents со свойством composed:true, если вы хотите, чтобы они пузырились вверх за границей shadowDOM

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

Удаление добавленных прослушивателей событий

class MyEl extends HTMLButtonElement {
  constructor() {
    super();
    let count = 0;// you do not have to stick everything on the Element
    let ME = this;//makes code easier to read and minifies better!
    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() просто как пример, эта функция НЕ удаляет элемент.

0 голосов
/ 28 февраля 2019

Это невозможно с вашей текущей реализацией - каждый вызов .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>
...