বাইন্ডের সাথে যুক্ত হওয়া ইভেন্ট শ্রোতাদের সরানো হচ্ছে


164

জাভাস্ক্রিপ্টে, বাইন্ড () ব্যবহার করে ইভেন্ট শ্রোতা হিসাবে যুক্ত কোনও ফাংশন সরানোর সর্বোত্তম উপায় কী?

উদাহরণ

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

})();

এটি করার আরও ভাল উপায় আছে?


2
আপনি ব্যতীত this.clickListener = this.clickListener.bind(this);আর কি করছেনthis.myButton.addEventListener("click", this.clickListener);
ইসাইলিজা

যে খুবই চমৎকার. এটি অন্যরকম বিষয় হতে পারে, তবে এটি আমাকে অবাক করে দিয়েছিল যে আমার বাকি পদ্ধতিগুলির জন্য "এই" কীওয়ার্ডটি ব্যবহার করা উচিত যদিও এটি পদ্ধতি কলকে অকার্যকর করে তোলে তার জন্য আমাকে বাঁধাই (এটি) করা উচিত কিনা।
তাকফুরুয়া

আমি সবসময় কনস্ট্রাক্টারে প্রথম পদ্ধতি হিসাবে এটি করি যে সমস্ত পদ্ধতি যে কোথাও পাস হতে চলেছে, নির্বিশেষে আমি সেগুলি পরে সরিয়ে ফেলছি কিনা। তবে সমস্ত পদ্ধতির জন্য নয়, কেবল তাদের চারপাশে পাস করা।
ইসাইলিজা

আপনি যা করছেন তা বোধগম্য। তবে এটি যদি কোনও লাইব্রেরির অংশ ছিল, উদাহরণস্বরূপ, আপনি কখনই জানতে পারবেন না যে কোন মাইক্লাসের পদ্ধতিগুলি ("পাবলিক" হিসাবে নথিভুক্ত) প্রায় পাস হবে be
তাকফুরুয়া

শুধু এফওয়াইআই, অ্যান্ডস্কোর লাইব্রেরিতে একটি bindAllফাংশন রয়েছে যা বাধ্যতামূলক পদ্ধতিগুলি সহজতর করে। আপনার অবজেক্ট ইনিশিয়ালাইজারের অভ্যন্তরে আপনি কেবল আপনার অবজেক্টের _.bindAll(this)প্রতিটি পদ্ধতিকে একটি বাউন্ড সংস্করণে সেট করতে করতে পারেন। অন্যথা, আপনি শুধুমাত্র কিছু পদ্ধতি (যা আমি বলতে চাই আপতিক মেমরি তথ্য ফাঁসের প্রতিরোধ) বাঁধে করতে চাই, আপনি তাদের আর্গুমেন্ট হিসাবে প্রদান করতে পারেন: _.bindAll(this, "foo", "bar") // this.baz won't be bound
মেশিনহোস্ট

উত্তর:


274

যদিও @ মেশিনঘোস্ট যা বলেছেন তা সত্য, ঘটনাগুলি একইভাবে যুক্ত করা এবং অপসারণ করা হলেও সমীকরণের অনুপস্থিত অংশটি হ'ল:

.bind()বলা হয়ে যাওয়ার পরে একটি নতুন ফাংশন রেফারেন্স তৈরি হয়!

দেখুন বাঁধাই () ফাংশন রেফারেন্স পরিবর্তন করে? | স্থায়ীভাবে কীভাবে সেট করবেন?

সুতরাং, এটি যুক্ত বা অপসারণ করতে, একটি ভেরিয়েবলের জন্য রেফারেন্স নির্ধারণ করুন:

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

এটি আমার প্রত্যাশার মতো কাজ করে।


4
দুর্দান্ত, এটি গ্রহণযোগ্য উত্তর হওয়া উচিত। একটি পুরানো বিষয় আপডেট করার জন্য ধন্যবাদ, এই বিষয়টি সার্চ ইঞ্জিনে এক নম্বর হিট হিসাবে উপস্থিত হয়েছিল এবং আপনি এখনই এটি পোস্ট না করা পর্যন্ত এর সঠিক সমাধান হয়নি।
বেলারঘ

এটি প্রশ্নের মধ্যে উল্লিখিত পদ্ধতির চেয়ে আলাদা (এবং এর চেয়ে ভাল নয়)।
পিটার তাসেং

আমি বুঝতে পারি না, আপনি কীভাবে ক্লিক ইভেন্টের সাথে এটি কাজ করেন, ধন্যবাদ
আলবার্তো আকুয়া

@ AlbertoAcuña আধুনিক ব্রাউজার ব্যবহার .addEventListener(type, listener)এবং .removeEventListener(type, listener)একটি উপাদান যোগ এবং ঘটনা মুছে ফেলার জন্য। উভয়ের জন্য, আপনি সমাধান হিসাবে listenerপরামিতি হিসাবে বর্ণিত ফাংশন রেফারেন্স "click"টাইপ হিসাবে পাস করতে পারেন । বিকাশকারী.মোজিলা.আর.ইন-
বেন

1
এটি আমাকে সহায়তা করে - যদিও এই উত্তরটি 4 বছর আগে পোস্ট করা হয়েছিল :)
ব্যবহারকারীর609021

46

ফ্লাক্স স্টোরটিতে / থেকে প্রতিক্রিয়া উপাদানটির শ্রোতাদের রেজিস্ট্রেশন / অপসারণ করার সময় যাদের এই সমস্যা রয়েছে তাদের জন্য আপনার উপাদানটির নির্মাতার সাথে নীচের লাইনগুলি যুক্ত করুন:

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


7
দুর্দান্ত কৌশল, তবে প্রতিক্রিয়া / ফ্লাক্সের কোনও কিছুর সাথে কী সম্পর্ক আছে?
পিটার তাসেং

এটি বিভিন্ন শ্রেনী বা প্রোটোটাইপ ফাংশন থেকে ইভেন্ট শ্রোতাদের যুক্ত এবং অপসারণ করার সময় সঠিক পন্থা হিসাবে উপস্থিত বলে মনে হয়, যা আমি বিশ্বাস করি এটির সাথে সংযোগটি প্রতিক্রিয়া উপাদান / শ্রেণীর ক্ষেত্রেও প্রয়োগ হয়। আপনি এটি একটি সাধারণ (যেমন, মূল) উদাহরণ স্তরে বাঁধাই করছেন।
কীথ ডিসি

1
this.onChange = this.onChange.bind(this)আসলে আমি এটিই খুঁজছিলাম ফাংশন thisচিরদিনের জন্য আবদ্ধ :)
Paweł

2

আপনি একটি সীমাবদ্ধ ফাংশন ব্যবহার করেন বা না তা বিবেচ্য নয়; আপনি এটিকে অন্য ইভেন্ট হ্যান্ডলারের মতোই সরান। যদি আপনার সমস্যাটি হয় যে বাউন্ড সংস্করণটি তার নিজস্ব অনন্য ফাংশন, আপনি হয় বাউন্ড সংস্করণগুলি ট্র্যাক রাখতে পারেন, বা এটি ব্যবহার করতে পারেনremoveEventListener একটি নির্দিষ্ট হ্যান্ডলার গ্রহণ না করে স্বাক্ষর করতে পারেন (অবশ্যই এটি একই ধরণের অন্যান্য ইভেন্ট হ্যান্ডলারগুলি সরিয়ে দেবে) )।

(পার্শ্ব নোট হিসাবে, addEventListenerসমস্ত ব্রাউজারে কাজ করে না; আপনার ইভেন্টটি হুক-আপগুলি আপনার ক্রস-ব্রাউজার উপায়ে করতে সত্যিই jQuery এর মতো একটি গ্রন্থাগার ব্যবহার করা উচিত Also এছাড়াও, jQuery এর নাম স্পেস ইভেন্টগুলির ধারণা রয়েছে যা অনুমতি দেয় আপনাকে "ক্লিক.ফু"-তে আবদ্ধ করতে হবে; যখন আপনি ইভেন্টটি সরাতে চান আপনি নির্দিষ্ট হ্যান্ডলারটি না জেনে বা অন্যান্য হ্যান্ডলারগুলি সরিয়ে না দিয়ে jQuery কে "সমস্ত foo ইভেন্টগুলি সরান" বলতে পারেন tell)


আইই ইস্যু সম্পর্কে আমি সচেতন। আমি এমন একটি অ্যাপ্লিকেশন বিকাশ করছি যা আইএন - আউট থাকায় ক্যানভাসের উপর প্রচুর নির্ভর করে। আইই 8 ক্যানভাসকে সমর্থন করে তবে সর্বনিম্নে। আইই 9 + অ্যাডএভেন্টলিস্টনার সমর্থন করে। jQuery এর নেমস্পিড ইভেন্টগুলি খুব ঝরঝরে দেখাচ্ছে। কেবলমাত্র আমি যে বিষয়টি নিয়ে চিন্তিত তা হ'ল দক্ষতা।
তাকফুরুয়া

JQuery লোকেরা তাদের লাইব্রেরিটি ভালভাবে সম্পাদন করতে খুব কঠোর পরিশ্রম করে, তাই আমি সে বিষয়ে খুব বেশি চিন্তা করব না। যাইহোক, আপনার কড়া ব্রাউজারের প্রয়োজনীয়তার কারণে আপনি তার পরিবর্তে জেপ্টো পরীক্ষা করে দেখতে চাইতে পারেন। এটি এক ধরণের jQuery এর স্কেলড ডাউন সংস্করণের মতো যা দ্রুততর তবে পুরানো ব্রাউজারগুলিকে সমর্থন করতে পারে না (এবং এর কিছু অন্যান্য সীমাও রয়েছে)।
মেশিনহোস্ট

JQuery নেমস্পিড ইভেন্টগুলি ব্যাপকভাবে ব্যবহৃত হয় এবং কার্যত কোনও পারফরম্যান্স সম্পর্কিত উদ্বেগ থাকে না। কাউকে এমন কোনও সরঞ্জাম ব্যবহার না করার কথা বলা যা তাদের কোডকে আরও সহজ এবং (তত যুক্তিযুক্তভাবে আরও বোঝার জন্য) সহজ করে তুলবে, ভয়ঙ্কর পরামর্শ হবে, বিশেষত যদি জিকুয়েরি এবং কল্পিত পারফরম্যান্স উদ্বেগের অযৌক্তিক ভয় থেকে এমনটি করা হয়।
মেশিনহোস্ট

1
কোন স্বাক্ষর হবে? অপসারণের তালিকাভুক্ত এমডিএন পৃষ্ঠাটি দেখায় যে প্রথম দুটি আর্গুমেন্ট উভয়েরই প্রয়োজন।
কোডার 12

আমার ভুল. আমি এই উত্তরটি লিখেছি বছর পেরিয়ে গেছে তবে আমি অবশ্যই jQuery এর পদ্ধতি offবা unbindপদ্ধতি সম্পর্কে ভাবছিলাম । কোনও উপাদানটিতে সমস্ত শ্রোতা অপসারণ করতে আপনাকে যুক্ত হওয়ার সাথে সাথে তাদের নজর রাখতে হবে (যা jQuery বা অন্যান্য গ্রন্থাগারগুলি আপনার জন্য করতে পারে)।
মেশিনঘোস্ট


1

লাইব্রেরিতে আমাদের সমস্যা ছিল আমরা পরিবর্তন করতে পারিনি। অফিস ফ্যাব্রিক ইউআই, যার অর্থ আমরা ইভেন্ট হ্যান্ডলার যুক্ত হওয়ার উপায়টি পরিবর্তন করতে পারিনি। আমরা যেভাবে এটা মীমাংসিত ওভাররাইট ছিল 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>

0

সমাধান এখানে:

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

0

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

}

-1

উপরের পরামর্শ মতো আপনি যদি 'অনক্লিক' ব্যবহার করতে চান তবে আপনি এটি চেষ্টা করতে পারেন:

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

আমি আসা করি এটা সাহায্য করবে.


-2

এটি কিছুক্ষণ হয়ে গেছে তবে এমডিএন এর একটি দুর্দান্ত ব্যাখ্যা দিয়েছে। এটি আমাকে এখানে স্টাফের চেয়ে বেশি সহায়তা করেছে।

MDN :: EventTarget.addEventListener - হ্যান্ডলারের মধ্যে "এই" এর মান

এটি হ্যান্ডেলএভেন্ট ফাংশনটির দুর্দান্ত বিকল্প দেয়।

এটি আবদ্ধ এবং আবদ্ধ ছাড়া একটি উদাহরণ:

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
}

উপরের উদাহরণে একটি সমস্যা হ'ল আপনি শ্রোতাদেরকে বাঁধাই দিয়ে সরাতে পারবেন না। আর একটি সমাধান হ'ল হ্যান্ডেল এভেন্ট নামে একটি বিশেষ ফাংশন ব্যবহার করে কোনও ইভেন্ট ধরতে পারে:

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.