Programing

바인드로 추가 된 이벤트 리스너 제거

lottogame 2020. 6. 16. 21:12
반응형

바인드로 추가 된 이벤트 리스너 제거


JavaScript에서 bind ()를 사용하여 이벤트 리스너로 추가 된 함수를 제거하는 가장 좋은 방법은 무엇입니까?

(function(){

    // constructor
    MyClass = function() {
        this.myButton = document.getElementById("myButtonID");
        this.myButton.addEventListener("click", this.clickListener.bind(this));
    };

    MyClass.prototype.clickListener = function(event) {
        console.log(this); // must be MyClass
    };

    // public method
    MyClass.prototype.disableButton = function() {
        this.myButton.removeEventListener("click", ___________);
    };

})();

내가 생각할 수있는 유일한 방법은 bind로 추가 된 모든 리스너를 추적하는 것입니다.

이 방법으로 위의 예 :

(function(){

    // constructor
    MyClass = function() {
        this.myButton = document.getElementById("myButtonID");
        this.clickListenerBind = this.clickListener.bind(this);
        this.myButton.addEventListener("click", this.clickListenerBind);
    };

    MyClass.prototype.clickListener = function(event) {
        console.log(this); // must be MyClass
    };

    // public method
    MyClass.prototype.disableButton = function() {
        this.myButton.removeEventListener("click", this.clickListenerBind);
    };

})();

더 좋은 방법이 있습니까?


@machineghost가 말한 것은 사실이지만 이벤트는 같은 방식으로 추가 및 제거되지만 방정식의 누락 부분은 다음과 같습니다.

.bind()호출 된 후 새로운 함수 참조가 생성됩니다 !

참조 합니까 바인드 () 함수 참조를 변경? | 영구적으로 설정하는 방법?

따라서 변수를 추가하거나 제거하려면 변수에 참조를 지정하십시오.

var x = this.myListener.bind(this);
Toolbox.addListener(window, 'scroll', x);
Toolbox.removeListener(window, 'scroll', x);

이것은 나에게 예상대로 작동합니다.


Flux 상점에 React 구성 요소의 리스너를 등록 / 제거하는 중에이 문제점이있는 사용자의 경우, 구성 요소의 생성자에 아래 행을 추가하십시오.

class App extends React.Component {
  constructor(props){
    super(props);
    // it's a trick! needed in order to overcome the remove event listener
    this.onChange = this.onChange.bind(this);  
  }
  // then as regular...
  componentDidMount (){
    AppStore.addChangeListener(this.onChange);
  }
  
  componentWillUnmount (){
    AppStore.removeChangeListener(this.onChange);
  }

  onChange () {
    let state = AppStore.getState();
    this.setState(state);
  }
  
  render() {
    // ...
  }
  
}


It doesn't matter whether you use a bound function or not; you remove it the same way as any other event handler. If your issue is that the bound version is its own unique function, you can either keep track of the bound versions, or use the removeEventListener signature that doesn't take a specific handler (although of course that will remove other event handlers of the same type).

(As a side note, addEventListener doesn't work in all browsers; you really should use a library like jQuery to do your event hook-ups in a cross-browser way for you. Also, jQuery has the concept of namespaced events, which allow you to bind to "click.foo"; when you want to remove the event you can tell jQuery "remove all foo events" without having to know the specific handler or removing other handlers.)


jQuery solution:

let object = new ClassName();
let $elem = $('selector');

$elem.on('click', $.proxy(object.method, object));

$elem.off('click', $.proxy(object.method, object));

Here is the solution:

var o = {
  list: [1, 2, 3, 4],
  add: function () {
    var b = document.getElementsByTagName('body')[0];
    b.addEventListener('click', this._onClick());

  },
  remove: function () {
    var b = document.getElementsByTagName('body')[0];
    b.removeEventListener('click', this._onClick());
  },
  _onClick: function () {
    this.clickFn = this.clickFn || this._showLog.bind(this);
    return this.clickFn;
  },
  _showLog: function (e) {
    console.log('click', this.list, e);
  }
};


// Example to test the solution
o.add();

setTimeout(function () {
  console.log('setTimeout');
  o.remove();
}, 5000);

We had this problem with a library we could not change. Office Fabric UI, which meant we could not change the way event handlers were added. The way we solved it was to overwrite the addEventListener on the EventTarget prototype.

This will add a new function on objects element.removeAllEventListers("click")

(original post: Remove Click handler from fabric dialog overlay)

        <script>
            (function () {
                "use strict";

                var f = EventTarget.prototype.addEventListener;

                EventTarget.prototype.addEventListener = function (type, fn, capture) {
                    this.f = f;
                    this._eventHandlers = this._eventHandlers || {};
                    this._eventHandlers[type] = this._eventHandlers[type] || [];
                    this._eventHandlers[type].push([fn, capture]);
                    this.f(type, fn, capture);
                }

                EventTarget.prototype.removeAllEventListeners = function (type) {
                    this._eventHandlers = this._eventHandlers || {};
                    if (type in this._eventHandlers) {
                        var eventHandlers = this._eventHandlers[type];
                        for (var i = eventHandlers.length; i--;) {
                            var handler = eventHandlers[i];
                            this.removeEventListener(type, handler[0], handler[1]);
                        }
                    }
                }

                EventTarget.prototype.getAllEventListeners = function (type) {
                    this._eventHandlers = this._eventHandlers || {};
                    this._eventHandlers[type] = this._eventHandlers[type] || [];
                    return this._eventHandlers[type];
                }

            })();
        </script>

can use about ES7:

class App extends React.Component {
  constructor(props){
    super(props);
  }
  componentDidMount (){
    AppStore.addChangeListener(this.onChange);
  }

  componentWillUnmount (){
    AppStore.removeChangeListener(this.onChange);
  }

  onChange = () => {
    let state = AppStore.getState();
    this.setState(state);
  }

  render() {
    // ...
  }

}

If you want to use 'onclick', as suggested above, you could try this:

(function(){
    var singleton = {};

    singleton = new function() {
        this.myButton = document.getElementById("myButtonID");

        this.myButton.onclick = function() {
            singleton.clickListener();
        };
    }

    singleton.clickListener = function() {
        console.log(this); // I also know who I am
    };

    // public function
    singleton.disableButton = function() {
        this.myButton.onclick = "";
    };
})();

I hope it helps.


It's been awhile but MDN has a super explanation on this. That helped me more than the stuff here.

MDN :: EventTarget.addEventListener - The value of "this" within the handler

It gives a great alternative to the handleEvent function.

This is an example with and without bind:

var Something = function(element) {
  this.name = 'Something Good';
  this.onclick1 = function(event) {
    console.log(this.name); // undefined, as this is the element
  };
  this.onclick2 = function(event) {
    console.log(this.name); // 'Something Good', as this is the binded Something object
  };
  element.addEventListener('click', this.onclick1, false);
  element.addEventListener('click', this.onclick2.bind(this), false); // Trick
}

A problem in the example above is that you cannot remove the listener with bind. Another solution is using a special function called handleEvent to catch any events:

참고URL : https://stackoverflow.com/questions/11565471/removing-event-listener-which-was-added-with-bind

반응형