2017-07-31 5 views
6

द्वारा डाले गए तत्व में क्लिक ईवेंट जोड़ें यदि मैं पहले "संपादन" पर क्लिक करता हूं तो मुझे console.log('click happend') मिलता है लेकिन यदि मैं इन बॉक्सों में से एक जावास्क्रिप्ट के माध्यम से जोड़ता हूं ("बॉक्स जोड़ें" पर क्लिक करें) और फिर click संपादित करें नया बॉक्स काम नहीं करता है। मुझे पता है क्योंकि जावास्क्रिप्ट तब चलता है जब तत्व वहां नहीं था और यही कारण है कि कोई ईवेंट इवेंट श्रोता नहीं है। मैं jQuery के साथ भी जानता हूं मैं ऐसा कर सकता था:जावास्क्रिप्ट

$('body').on('click', '.edit', function(){ // do whatever }; 

और यह काम करेगा।

लेकिन मैं इसे सादा जावास्क्रिप्ट के साथ कैसे कर सकता हूं? मुझे कोई सहायक संसाधन नहीं मिला। एक साधारण उदाहरण बनाया जो मैं काम करना चाहता हूं। इसे हल करने का सबसे अच्छा तरीका क्या है?

तो समस्या यह है कि: यदि आप एक बॉक्स जोड़ते हैं और फिर "संपादित करें" पर क्लिक करें तो कुछ भी नहीं होता है।

var XXX = {}; 
 
XXX.ClickMe = function(element){ 
 
    this.element = element; 
 
    
 
    onClick = function() { 
 
     console.log('click happend'); 
 
    }; 
 
    
 
    this.element.addEventListener('click', onClick.bind(this)); 
 
}; 
 

 
[...document.querySelectorAll('.edit')].forEach(
 
    function (element, index) { 
 
     new XXX.ClickMe(element); 
 
    } 
 
); 
 

 

 
XXX.PrototypeTemplate = function(element) { 
 
    this.element = element; 
 
    var tmpl = this.element.getAttribute('data-prototype'); 
 

 
    addBox = function() { 
 
     this.element.insertAdjacentHTML('beforebegin', tmpl); 
 
    }; 
 

 
    this.element.addEventListener('click', addBox.bind(this)); 
 
}; 
 

 

 
[...document.querySelectorAll('[data-prototype]')].forEach(
 
    function (element, index) { 
 
     new XXX.PrototypeTemplate(element); 
 
    } 
 
);
[data-prototype] { 
 
    cursor: pointer; 
 
}
<div class="box"><a class="edit" href="#">Edit</a></div> 
 

 
<span data-prototype="<div class=&quot;box&quot;><a class=&quot;edit&quot; href=&quot;#&quot;>Edit</a></div>">Add box</span>

JSFiddle here

This Q/A is useful information लेकिन यह कैसे समस्या को हल करने पर मेरे सवाल का जवाब नहीं है। मैं उन तत्वों के लिए new XXX.ClickMe(element); जैसे ईवेंट लिस्टनर को कैसे शुरू कर सकता हूं जैसे डीओएम में गतिशील रूप से डाला गया?

+0

की संभावित डुप्लिकेट [डोम घटना प्रतिनिधिमंडल क्या है?] (Https://stackoverflow.com/questions/1687296/what-is-dom-event-delegation: एक आकर्षण की तरह काम करता है) –

उत्तर

2

यहाँ एक विधि है कि नकल करता है $('body').on('click', '.edit', function() { ... }) है ClickMe() के प्रत्येक उदाहरण के लिए कमजोर संदर्भ रखें, जो ईवेंट प्रतिनिधि को अनुमति देता है प्रत्येक .edit तत्व के लिए केवल एक उदाहरण शुरू करके कुशलतापूर्वक प्रतिनिधि बनने के लिए, और फिर स्थिर विधि ClickMe.get(element) के माध्यम से भावी प्रतिनिधि क्लिक पर पहले से बनाए गए उदाहरण का संदर्भ दे रहा है।

कमजोर संदर्भ ClickMe() के उदाहरणों को कचरा इकट्ठा करने की अनुमति देते हैं यदि उसकी तत्व कुंजी को कभी भी डोम से हटा दिया जाता है और बाहर के दायरे में पड़ता है।

+0

धन्यवाद पैट्रिक, इससे बहुत मदद मिलती है ! +1 – caramba

+1

@caramba वास्तव में मुझे एहसास हुआ कि मैंने ईवेंट प्रतिनिधिमंडल का उपयोग नहीं किया है, बस उसमें काम किया है, –

2

आप कुछ इस तरह कर सकते हैं ...

document.addEventListener('click',function(e){ 
    if(e.target && e.target.className.split(" ")[0]== 'edit'){ 
    new XXX.ClickMe(e.target);} 
}) 

var XXX = {}; 
 
XXX.ClickMe = function(element) { 
 
    this.element = element; 
 

 

 
    this.element.addEventListener('click', onClick.bind(this)); 
 
}; 
 

 

 

 
XXX.PrototypeTemplate = function(element) { 
 
    this.element = element; 
 
    var tmpl = this.element.getAttribute('data-prototype'); 
 

 
    addBox = function() { 
 
    this.element.insertAdjacentHTML('beforebegin', tmpl); 
 
    }; 
 

 
    this.element.addEventListener('click', addBox.bind(this)); 
 
}; 
 

 

 
[...document.querySelectorAll('[data-prototype]')].forEach(
 
    function(element, index) { 
 
    new XXX.PrototypeTemplate(element); 
 
    } 
 
); 
 

 

 
document.addEventListener('click', function(e) { 
 
    if (e.target && e.target.className.split(" ")[0] == 'edit') { 
 
    console.log('click happend'); 
 
    } 
 
})
[data-prototype] { 
 
    cursor: pointer; 
 
}
<div class="box"><a class="edit" href="#">Edit</a></div> 
 

 
<span data-prototype="<div class=&quot;box&quot;><a class=&quot;edit&quot; href=&quot;#&quot;>Edit</a></div>">Add box</span>

+0

मान लीजिए कि एक गायब जगह 'me.split ("") [0] [यहां] ==' संपादित करें 'मुझे पसंद नहीं है [यह fiddle] (https://jsfiddle.net/noeuesps/1/)। कभी-कभी मुझे कोई क्लिक नहीं मिलता है, कभी-कभी दो। बस अच्छा और साफ नहीं लगता – caramba

+0

हां क्योंकि आपको अपना कोड ट्विक करने की आवश्यकता है। यदि आप इस कोड का उपयोग दूसरे के साथ करते हैं, तो क्लिक के कई बाध्यकारी होंगे – Tushar

+0

@caramba मैंने आपके पहेली को अपडेट किया है। https://jsfiddle.net/bwveoyrz/। अब काम करता है – Tushar

2

jQuery की तरह इसे अभी करें: एक माता पिता के तत्व यह है कि घटना के प्रतिनिधिमंडल को नियंत्रित करता है। निम्नलिखित में, मैं माता पिता के रूप document.body का उपयोग करें:

document.body.addEventListener('click', e => { 
    if (e.target.matches('.edit')) { 
    // do whatever 
    } 
}); 

कार्य उदाहरण:

var XXX = {}; 
 
XXX.PrototypeTemplate = function(element) { 
 
    this.element = element; 
 
    var tmpl = this.element.getAttribute('data-prototype'); 
 
    addBox = function() { 
 
    this.element.insertAdjacentHTML('beforebegin', tmpl); 
 
    }; 
 
    this.element.addEventListener('click', addBox.bind(this)); 
 
}; 
 

 

 
new XXX.PrototypeTemplate(document.querySelector('[data-prototype]')); 
 

 
document.body.addEventListener('click', e => { 
 
    if (e.target.matches('.edit')) { 
 
    // do whatever 
 
    console.log('click happend'); 
 
    } 
 
});
[data-prototype] { 
 
    cursor: pointer; 
 
}
<div class="box"><a class="edit" href="#">Edit</a></div> 
 
<span data-prototype="<div class=&quot;box&quot;><a class=&quot;edit&quot; href=&quot;#&quot;>Edit</a></div>">Add box</span>

क्या MDN Element.prototype.matches के बारे में कहते हैं पर एक नजर डालें।

document.body.addEventListener('click', function (event) { 
    if (event.target.classList.contains('edit')) { 
    ... 
    } 
}) 

कार्य है कि अपने उदाहरण में (मैं एक छोटे से संशोधित करेंगे जो):

var XXX = { 
 
    refs: new WeakMap(), 
 
    ClickMe: class { 
 
    static get (element) { 
 
     // if no instance created 
 
     if (!XXX.refs.has(element)) { 
 
     console.log('created instance') 
 
     // create instance 
 
     XXX.refs.set(element, new XXX.ClickMe(element)) 
 
     } else { 
 
     console.log('using cached instance') 
 
     } 
 
     
 
     // return weakly referenced instance 
 
     return XXX.refs.get(element) 
 
    } 
 

 
    constructor (element) { 
 
     this.element = element 
 
    } 
 
    
 
    onClick (event) { 
 
     console.log('click happened') 
 
    } 
 
    }, 
 
    PrototypeTemplate: class { 
 
    constructor (element) { 
 
     this.element = element 
 
     
 
     var templateSelector = this.element.getAttribute('data-template') 
 
     var templateElement = document.querySelector(templateSelector) 
 
     // use .content.clone() to access copy fragment inside of <template> 
 
     // using template API properly, but .innerHTML would be more compatible 
 
     this.template = templateElement.innerHTML 
 
     
 
     this.element.addEventListener('click', this.addBox.bind(this)) 
 
    } 
 
    
 
    addBox() { 
 
     this.element.insertAdjacentHTML('beforeBegin', this.template, this.element) 
 
    } 
 
    } 
 
} 
 

 
Array.from(document.querySelectorAll('[data-template]')).forEach(function (element) { 
 
    // just insert the first one here 
 
    new XXX.PrototypeTemplate(element).addBox() 
 
}) 
 

 
// event delegation instead of individual ClickMe() event listeners 
 
document.body.addEventListener('click', function (event) { 
 
    if (event.target.classList.contains('edit')) { 
 
    console.log('delegated click') 
 
    // get ClickMe() instance for element, and create one if necessary 
 
    // then call its onClick() method using delegation 
 
    XXX.ClickMe.get(event.target).onClick(event) 
 
    } 
 
})
[data-template] { 
 
    cursor: pointer; 
 
} 
 

 
/* compatibility */ 
 
template { 
 
    display: none; 
 
}
<span data-template="#box-template">Add box</span> 
 

 
<template id="box-template"> 
 
    <div class="box"> 
 
    <a class="edit" href="#">Edit</a> 
 
    </div> 
 
</template>

यह करने के लिए WeakMap() का उपयोग करता

+0

मैं भी यह जानना चाहता हूं। यह आपके 'नए XXX.ClickMe (तत्व);' डिज़ाइन के साथ अच्छी तरह से काम नहीं करता है, लेकिन इसे कुछ बदलावों के साथ काम करना चाहिए। – PeterMader

+0

अब मेरी समस्या के लिए धन्यवाद, ऑब्जेक्ट 'XXX.ClickMe() 'में अलग-अलग गुण हैं जो वे सभी खो गए हैं। इसलिए मैं 'नया XXX' का आह्वान करना या तत्काल करना चाहता हूं। क्लिक करें (तत्व); ' – caramba

+0

आप ईवेंट प्रतिनिधिमंडल और' XXX.ClickMe' का उपयोग उसी समय नहीं कर सकते। आप निश्चित रूप से 'XXX.ClickMe की एक सरणी रख सकते हैं और जब भी कोई तत्व क्लिक किया जाता है तो वह एक नया जोड़ता है जो सरणी में नहीं है। लेकिन मैं आपको घटना प्रतिनिधिमंडल के बिना 'एडबॉक्स' में एक नया 'XXX.ClickMe' बनाने की सलाह देता हूं। – PeterMader

0

सभी सवालों के जवाब देने के लिए धन्यवाद, यह सभी सहायक जानकारी है। निम्नलिखित के बारे में क्या:

XXX.InitializeAllFunctions = function(wrap) {} के अंदर आवश्यक सभी कार्यों को लपेटें और document को पहले पृष्ठ लोड पर रैप के रूप में पास करें। तो यह पहले जैसा करता है जैसा व्यवहार करता है। नए डोम तत्वों को सम्मिलित करते समय बस उन कार्यों को डीओएम में डालने से पहले पास करें।

var XXX = {}; 
 

 
XXX.ClickMe = function(element){ 
 
    this.element = element; 
 
    onClick = function() { 
 
     console.log('click happend'); 
 
    }; 
 
    this.element.addEventListener('click', onClick.bind(this)); 
 
}; 
 

 
XXX.PrototypeTemplate = function(element) { 
 
    this.element = element; 
 

 
    addBox = function() { 
 
     var tmpl = this.element.getAttribute('data-prototype'); 
 
     var html = new DOMParser().parseFromString(tmpl, 'text/html'); 
 

 
     XXX.InitializeAllFunctions(html); // Initialize here on all new HTML 
 
              // before inserting into DOM 
 

 
     this.element.parentNode.insertBefore(
 
      html.body.childNodes[0], 
 
      this.element 
 
     ); 
 
    }; 
 

 
    this.element.addEventListener('click', addBox.bind(this)); 
 
}; 
 

 
XXX.InitializeAllFunctions = function(wrap) { 
 

 
    var wrap = wrap == null ? document : wrap; 
 

 
    [...wrap.querySelectorAll('[data-prototype]')].forEach(
 
     function (element, index) { 
 
      new XXX.PrototypeTemplate(element); 
 
     } 
 
    ); 
 

 
    [...wrap.querySelectorAll('.edit')].forEach(
 
     function (element, index) { 
 
      new XXX.ClickMe(element); 
 
     } 
 
    ); 
 
}; 
 

 
XXX.InitializeAllFunctions(document);
[data-prototype] { 
 
    cursor: pointer; 
 
}
<div class="box"><a class="edit" href="#">Edit</a></div> 
 
<span data-prototype="<div class=&quot;box&quot;><a class=&quot;edit&quot; href=&quot;#&quot;>Edit</a></div>">Add box</span>

+0

संपादित करें ठीक है, यह आपके द्वारा अनुरोधित ईवेंट प्रतिनिधिमंडल का उपयोग नहीं करता है। प्रत्येक '.edit' में अपना 'this.element.addEventListener (' क्लिक ', onClick.bind (यह)) है, इसलिए आप फ्लाई पर कई स्कोप्ड फ़ंक्शंस उत्पन्न कर रहे हैं। इसके विपरीत, मेरा उत्तर घटना के प्रतिनिधिमंडल का उपयोग 'क्लिकमे' के उदाहरण बनाने के लिए करता है, लेकिन प्रत्येक के लिए इवेंट श्रोता को बाध्य नहीं करता है, बल्कि एक प्रतिनिधिमंडल ईवेंट श्रोता से इसकी सदस्य विधि को आमंत्रित करता है। –

+0

@PatrickRoberts वापस और टिप्पणी की जांच के लिए धन्यवाद! बहुत सराहना की! – caramba

संबंधित मुद्दे