2012-07-19 15 views
99

के साथ जोड़ा गया ईवेंट श्रोता को हटाकर जावास्क्रिप्ट में, बाइंड() का उपयोग करके ईवेंट श्रोता के रूप में जोड़े गए फ़ंक्शन को निकालने का सबसे अच्छा तरीका क्या है?बाइबल

उदाहरण

(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.myButton.addEventListener (" क्लिक "यह, .clickListener); ' – Esailija

+0

यह बहुत अच्छा है। यह एक अलग विषय हो सकता है, लेकिन इससे मुझे आश्चर्य हुआ कि मुझे अपनी शेष विधियों के लिए बाध्य करना चाहिए (यह) "इस" कीवर्ड का उपयोग करें, भले ही यह विधि अक्षम अक्षम करे। – takfuruya

+0

मैं हमेशा उन सभी विधियों के लिए कन्स्ट्रक्टर में पहली चीज़ के रूप में ऐसा करता हूं जो कहीं भी पारित होने जा रहे हैं, भले ही मैं उन्हें बाद में हटाने जा रहा हूं। लेकिन सभी विधियों के लिए नहीं, बस जो पास हो जाते हैं। – Esailija

उत्तर

178

इस हालांकि @machineghost क्या कहा सच था, कि घटनाओं जोड़ा गया है और उसी तरह से हटा दिया जाता है, समीकरण के लापता हिस्सा था:

एक नया समारोह संदर्भ बनाई गई है .bind() के बाद कहा जाता है!

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

यह काम करता है के रूप में मेरे लिए उम्मीद:

Does bind() change the function reference? | How to set permanently?

तो, जोड़ सकते हैं या इसे हटाने के लिए, संदर्भ में एक चर के लिए असाइन देखें।

+2

उत्कृष्ट, यह स्वीकार्य उत्तर होना चाहिए। पुराने विषय को अपडेट करने के लिए धन्यवाद, यह विषय खोज इंजन पर नंबर एक हिट के रूप में आया था और जब तक आप इसे पोस्ट नहीं करते हैं तब तक इसका कोई उचित समाधान नहीं था। – Blargh

+0

धन्यवाद जो अपेक्षित के रूप में काम करता है! –

+0

यह प्रश्न में उल्लिखित विधि से अलग नहीं है (और इससे बेहतर नहीं)। –

5

इससे कोई फर्क नहीं पड़ता कि आप बाध्य कार्य का उपयोग करते हैं या नहीं; आप इसे किसी अन्य घटना हैंडलर के समान ही हटा देते हैं। यदि आपकी समस्या यह है कि बाध्य संस्करण अपना अनूठा कार्य है, तो आप या तो बाध्य संस्करणों का ट्रैक रख सकते हैं, या removeEventListener हस्ताक्षर का उपयोग कर सकते हैं जो एक विशिष्ट हैंडलर नहीं लेता है (हालांकि निश्चित रूप से यह अन्य ईवेंट हैंडलर को हटा देगा प्रकार)।

(एक साइड नोट के रूप में, addEventListener सभी ब्राउज़रों में काम नहीं करता है; आपको वास्तव में आपके लिए एक क्रॉस-ब्राउज़र तरीके से अपने ईवेंट हुक-अप करने के लिए jQuery जैसी लाइब्रेरी का उपयोग करना चाहिए। इसके अलावा, jQuery की अवधारणा है नामांकित घटनाएं, जो आपको "click.foo" से जुड़ने की अनुमति देती हैं; जब आप ईवेंट को हटाना चाहते हैं तो आप विशिष्ट हैंडलर को जानने या अन्य हैंडलर को हटाने के बिना jQuery को "सभी foo ईवेंट हटाएं" बता सकते हैं।)

+0

मुझे आईई मुद्दे से अवगत है। मैं एक ऐसा एप्लीकेशन विकसित कर रहा हूं जो कैनवास पर भारी निर्भर करता है ताकि आई 7- बाहर हो। आईई 8 कैनवास का समर्थन करता है लेकिन कम से कम। IE9 + addEventListener का समर्थन करता है। jQuery की नामांकित घटनाएं बहुत साफ दिखती हैं। केवल एक चीज जिसे मैं चिंतित करता हूं वह दक्षता है। – takfuruya

+0

jQuery लोग काम करते हैं * अपनी लाइब्रेरी को अच्छी तरह से प्रदर्शन करने के लिए बहुत कठिन *, इसलिए मैं इसके बारे में ज्यादा चिंता नहीं करता। हालांकि, अपनी सख्त ब्राउज़र आवश्यकताओं को देखते हुए आप इसके बजाय ज़ेप्टो को देखना चाहेंगे। यह jQuery के स्केल किए गए संस्करण की तरह है जो तेज़ है लेकिन पुराने ब्राउज़र का समर्थन नहीं कर सकता (और इसमें कुछ अन्य सीमाएं हैं)। – machineghost

+0

"मैं इसके बारे में ज्यादा चिंता नहीं करता ...." भयानक सलाह – 1dayitwillmake

-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 - The value of "this" within the handler

यह 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 
} 

ऊपर के उदाहरण में एक समस्या यह है कि आप बाँध के साथ श्रोता नहीं निकाल सकते है।एक अन्य समाधान किसी भी घटना को पकड़ने के लिए हैंडलएवेंट नामक एक विशेष समारोह का उपयोग कर रहा है:

31

उन लोगों के लिए जिनके पास फ्लक्स स्टोर से/रिएक्ट घटक के श्रोता घटक को पंजीकृत/हटाते समय समस्या है, नीचे दिए गए लाइनों को अपने घटक के कन्स्ट्रक्टर में जोड़ें:

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

+4

अच्छी चाल है, लेकिन प्रतिक्रिया/प्रवाह को किसी भी चीज़ के साथ क्या करना है? –

+0

Thx, यह वास्तव में बहुत अच्छा समाधान है :) – Arcagully

+0

यह विभिन्न श्रोताओं या प्रोटोटाइप कार्यों से ईवेंट श्रोताओं को जोड़ने और हटाने के दौरान सही दृष्टिकोण प्रतीत होता है, जिसका मेरा मानना ​​है कि इसके साथ संबंध घटकों/वर्गों पर भी लागू होता है। आप इसे एक सामान्य (उदा।, रूट) उदाहरण स्तर पर बाध्य कर रहे हैं। –

-1

< शेख़ी > यह 2016 है और डोम मानक हम अब और फिर हर हिट एक बहुत ही आम समस्या को हल करने में ज्यादा नहीं मदद की है। </rant >

हां एक बाध्य घटना हैंडलर को हटाने का एकमात्र तरीका बाध्य कार्य का संदर्भ रखना है और इसे अन्य समाधानों में बताए गए निकालने के लिए हटाएं।

हालांकि जब आपको कई श्रोताओं मिलते हैं तो यह गन्दा हो जाता है। कोई भी सरल कार्यों के साथ नहीं आया है जो बाध्य कार्यों के संदर्भ रखने के काम को सारणीबद्ध करता है। मैं() और ऑफ() (jQuery प्रेरित नाम) नामक दो कार्यों के साथ आया हूं जो मैंने प्रोटोटाइप में जोड़कर सभी HTMLElements में जोड़ा है। Code's here। (आईई पर केवल काम करता है 11+ के बाद से यह WeakMap उपयोग करता है)

ताकि का उपयोग कर आप घटना श्रोताओं को जोड़ने और उन्हें इतनी तरह निकाल सकते हैं:

this.myButton.on('click', this.clickListener, this); 
this.myButton.off('click', this.clickListener, this); //yup, it's removed 

कार्यान्वयन विवरण और लिए गए निर्णयों में कई हैं, तो मैं जीता इसे समझाओ :)

यदि आप मूल वस्तुओं में फ़ंक्शंस जोड़ने को पसंद नहीं करते हैं, तो आप मेरे कोड को थोड़ा सा संपादित करके प्राप्त कर सकते हैं। (लेकिन गंभीरता से, डीओएम मानक को हमारे लिए इसे पहले स्थान पर हल करने के लिए कुछ एपीआई जोड़ा जाना चाहिए था)।

+0

हैलो, फ़ेलिक्स क्लिंग के उत्तर में घटनाओं के संदर्भों को संदर्भित करने के इस अच्छे अमूर्तता को देखें: http://stackoverflow.com/questions/5660131/how-to-removeeventlistener-that-is-addeventlistener-with-anonymous-function –

+0

उनका समाधान अभी भी एक ही गड़बड़ है। मुझे अभी भी कोड में हैंडलर संदर्भ रखना है। मेरे पास ऐसे फाइलरों में ऐसे हैंडलर के 6 संदर्भ हैं जिनके पास कुछ ड्रैग और ड्रॉप ऑपरेशंस थे (ड्रॉप इत्यादि के बाद इवेंट श्रोता को हटाने के उद्देश्य से)। और मेरे पास समान जरूरतों के साथ कुछ और फाइलें थीं। और मेरी एकमात्र आवश्यकता यह थी कि ईवेंट हैंडलर का 'यह' कीवर्ड ऑब्जेक्ट उदाहरण होना चाहिए जिससे श्रोता जोड़ा गया था। समाधान में मैंने ऊपर प्रस्तुत किया है, हैंडलर संदर्भ रखने की कोई आवश्यकता नहीं है। – Munawwar

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