source

바인드를 사용하여 추가된 이벤트 수신기를 제거하는 중

nicesource 2022. 11. 4. 21:25
반응형

바인드를 사용하여 추가된 이벤트 수신기를 제거하는 중

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", ___________);
    };

})();

제가 생각할 수 있는 유일한 방법은 바인드가 추가된 모든 청취자를 추적하는 것입니다.

위의 예에서는 이 방법을 사용합니다.

(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()호출됩니다.

bind()함수 참조를 변경합니까? 참조하십시오. | 영속적인 설정 방법

따라서 참조를 추가하거나 제거하려면 변수에 참조를 할당합니다.

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

이건 예상대로 되는군요.

플럭스 스토어에서 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() {
    // ...
  }
  
}

바인딩된 함수를 사용하든 사용하지 않든 상관없습니다. 다른 이벤트 핸들러와 동일한 방법으로 함수를 제거합니다.바인딩된 버전이 고유한 기능인 경우 바인딩된 버전을 추적하거나removeEventListener특정 핸들러를 사용하지 않는 시그니처(물론 같은 유형의 다른 이벤트핸들러는 삭제됩니다)

(부록으로,addEventListenerjQuery와 같은 라이브러리를 사용하여 크로스 브라우저 방식으로 이벤트 연결을 수행해야 합니다.또한 jQuery에는 namesledevents라는 개념이 있습니다.이러한 이벤트를 삭제하려면 특정 핸들러나 다른 핸들러를 삭제하지 않고 jQuery에게 "remove all foo events"를 알릴 수 있습니다.)

jQuery 솔루션:

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

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

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

변경할 수 없는 라이브러리에서 이 문제가 발생했습니다.Office Fabric UI(이벤트 핸들러의 추가 방법을 변경할 수 없습니다)그 문제를 해결한 방법은 그 문제를addEventListener에서EventTarget프로토타입입니다.

그러면 개체에 새 기능이 추가됩니다.element.removeAllEventListers("click")

(원래 게시물: 패브릭 대화 상자 오버레이에서 클릭 핸들러 제거)

        <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>

해결책은 다음과 같습니다.

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);

다른 사람들이 말했듯이bind는 새로운 함수인스턴스를 만듭니다.따라서 이벤트청취자는 어떤 방법으로든 녹음되지 않는 한 삭제할 수 없습니다.

보다 아름다운 코드 스타일을 위해 메서드 함수를 느린 getter로 만들어 처음 액세스할 때 바인딩된 버전으로 자동 대체되도록 할 수 있습니다.

class MyClass {
  activate() {
    window.addEventListener('click', this.onClick);
  }

  deactivate() {
    window.removeEventListener('click', this.onClick);
  }

  get onClick() {
    const func = (event) => {
      console.log('click', event, this);
    };
    Object.defineProperty(this, 'onClick', {value: func});
    return func;
  }
}

되지 않는 경우 를 사용합니다.const func = (function(event){...}).bind(this)const func = (event) => {...}.

Raichman Sergey의 접근법 또한 좋다, 특히 수업에서.이 접근방식의 장점은 자기완성이 뛰어나고 다른 장소에서 분리된 코드가 없다는 것입니다.또한 생성자 또는 이니시에이터가 없는 개체에도 작동합니다.

위와 같이 '클릭'을 사용하려면 다음을 시도해 보십시오.

(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 = "";
    };
})();

도움이 됐으면 좋겠어요.

는 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() {
    // ...
  }

}

오랜만이긴 한데 MDN의 설명이 대단하네요.그건 여기 있는 것들보다 더 큰 도움이 되었어요.

MDN : EventTarget.addEventListener - 핸들러 내의 "this" 값

handleEvent 함수에 대한 훌륭한 대체 기능을 제공합니다.

다음 예에서는 바인드를 사용하는 경우와 사용하지 않는 경우를 보여 줍니다.

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
}

위의 예에서는 바인드를 사용하여 리스너를 삭제할 수 없다는 문제가 있습니다.또 다른 솔루션은 handleEvent라는 특수 함수를 사용하여 이벤트를 포착하고 있습니다.

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

반응형