2013-02-27 204 views
11

मैं इस समारोह का स्रोत नहीं देखा है, लेकिन मुझे आश्चर्य है कि यह इस प्रकार काम करता है: उन्हें jQuery.on() कैसे काम करता है?

  • -
  • प्रतिनिधियों प्रदान की घटना संचालकों उनके selecotrs द्वारा

    1. चयन तत्व (रों) कि चयनकर्ता और लगातार अन-delegating पर एक setInterval चलाता है, और उसके बाद फिर से सौंपने के सभी

    या वहाँ इस के लिए एक शुद्ध जावास्क्रिप्ट डोम विवरण है से अधिक है कि एक ही घटना?

  • उत्तर

    15

    मुझे लगता है आपके सवाल का .on की Event Delegation संस्करण के बारे में है।

    जावास्क्रिप्ट में, सबसे घटनाओं bubble डोम पदानुक्रम में ऊपर। इसका मतलब है, जब एक घटना जो तत्व के लिए आग लगती है, तो यह document स्तर तक डीओएम तक पहुंच जाएगी।

    इस बुनियादी मार्कअप पर विचार करें:

    <div> 
        <span>1</span> 
        <span>2</span> 
    </div> 
    

    अब हम घटना प्रतिनिधिमंडल लागू होते हैं:

    $('div').on('click', 'span', fn); 
    

    ईवेंट हैंडलर div तत्व को पूरी तरह से जुड़ा हुआ है। spandiv के अंदर हैं, फैला में कोई भी क्लिक करेंगे बुलबुला div अप करने के लिए, div के क्लिक हैंडलर फायरिंग। उस पल में, जो कुछ बचा है, यह जांच रहा है कि event.target (या लक्ष्य के बीच के किसी भी तत्व और delegateTarget) प्रतिनिधिमंडल लक्ष्य चयनकर्ता से मेल खाता है या नहीं।


    के एक सा अधिक जटिल बना दो:

    <div id="parent"> 
        <span>1</span> 
        <span>2 <b>another nested element inside span</b></span> 
        <p>paragraph won't fire delegated handler</p> 
    </div> 
    

    बुनियादी तर्क इस प्रकार है:

    //attach handler to an ancestor 
    document.getElementById('parent').addEventListener('click', function(e) { 
        //filter out the event target 
        if (e.target.tagName.toLowerCase() === 'span') { 
         console.log('span inside parent clicked'); 
        } 
    }); 
    

    हालांकि जब event.target अपने फिल्टर के अंदर नेस्टेड है ऊपर से मेल नहीं खाएगी। के रूप में jQuery के .on करता है केवल वंशज तत्वों के लिए अपडेट कर कोड:

    document.getElementById('parent').addEventListener('click', function(e) { 
        var failsFilter = true, 
         el = e.target; 
        while (el !== this && (failsFilter = el.tagName.toLowerCase() !== 'span') && (el = el.parentNode)); 
        if (!failsFilter) { 
         console.log('span inside parent clicked'); 
        } 
    }); 
    

    Fiddle

    संपादित करें: हम कुछ यात्रा तर्क की जरूरत है।

    नोट: ये स्निपेट व्याख्यात्मक उद्देश्यों के लिए हैं, वास्तविक दुनिया में उपयोग नहीं किए जाते हैं। जब तक आप पुराने आईई का समर्थन करने की योजना नहीं बनाते हैं, बेशक। पुराने IE के लिए आप इस तरह की जाँच घटना वस्तु वैश्विक दायरे में समारोह या उपलब्ध हैंडलर के लिए पारित किया गया है या नहीं के रूप में addEventListener/attachEvent के साथ-साथ event.target || event.srcElement, और संभवतः के खिलाफ परीक्षण सुविधा के लिए कुछ अन्य quirks की आवश्यकता होगी। शुक्र है कि jQuery हमारे लिए दृश्यों के पीछे निर्बाध रूप से सभी करता है।=]

    +0

    अच्छी तरह से यह सब ठीक है
    शायद ज़रुरत किसी में पर JQuery को बदलने के लिए/वेनिला-जावास्क्रिप्ट के साथ रहती जरूरत jQuery के बारे में और jQuery.on() का उपयोग कैसे करें, मुझे दिलचस्पी है कि केवल जावास्क्रिप्ट और डोम पर एक समान स्निपेट लिखना संभव है? –

    +0

    @Zlatan हां यह है। हालांकि बिना झुकाव के आपके पास कई फैंसी प्रतिनिधिमंडल चयनकर्ता नहीं होंगे। मैं एक शुद्ध जेएस एक उदाहरण जोड़ दूंगा। –

    +0

    ठीक है। खैर मुझे लगता है कि आप इसके साथ एक उदाहरण लिख सकते हैं: 'document.querySelector()' या 'document.querySelectorAll()' :) –

    2

    Necromancing:

    टाइपप्रति:

    /// attach an event handler, now or in the future, 
    /// for all elements which match childselector, 
    /// within the child tree of the element maching parentSelector. 
    export function subscribeEvent(parentSelector: string | Element 
        , eventName: string 
        , childSelector: string 
        , eventCallback) 
    { 
        if (parentSelector == null) 
         throw new ReferenceError("Parameter parentSelector is NULL"); 
    
        if (childSelector == null) 
         throw new ReferenceError("Parameter childSelector is NULL"); 
    
        // nodeToObserve: the node that will be observed for mutations 
        let nodeToObserve: Element = <Element>parentSelector; 
        if (typeof (parentSelector) === 'string') 
         nodeToObserve = document.querySelector(<string>parentSelector); 
    
    
        let eligibleChildren: NodeListOf<Element> = nodeToObserve.querySelectorAll(childSelector); 
    
        for (let i = 0; i < eligibleChildren.length; ++i) 
        { 
         eligibleChildren[i].addEventListener(eventName, eventCallback, false); 
        } // Next i 
    
        // https://stackoverflow.com/questions/2712136/how-do-i-make-this-loop-all-children-recursively 
        function allDescendants(node: Node) 
        { 
         if (node == null) 
          return; 
    
         for (let i = 0; i < node.childNodes.length; i++) 
         { 
          let child = node.childNodes[i]; 
          allDescendants(child); 
         } // Next i 
    
         // IE 11 Polyfill 
         if (!Element.prototype.matches) Element.prototype.matches = Element.prototype.msMatchesSelector; 
    
         if ((<Element>node).matches) 
         { 
          if ((<Element>node).matches(childSelector)) 
          { 
           // console.log("match"); 
           node.addEventListener(eventName, eventCallback, false); 
          } // End if ((<Element>node).matches(childSelector)) 
          // else console.log("no match"); 
    
         } // End if ((<Element>node).matches) 
         // else console.log("no matchfunction"); 
    
        } // End Function allDescendants 
    
    
        // Callback function to execute when mutations are observed 
        let callback:MutationCallback = function (mutationsList: MutationRecord[], observer: MutationObserver) 
        { 
         for (let mutation of mutationsList) 
         { 
          // console.log("mutation.type", mutation.type); 
          // console.log("mutation", mutation); 
    
          if (mutation.type == 'childList') 
          { 
           for (let i = 0; i < mutation.addedNodes.length; ++i) 
           { 
            let thisNode: Node = mutation.addedNodes[i]; 
            allDescendants(thisNode); 
           } // Next i 
    
          } // End if (mutation.type == 'childList') 
          // else if (mutation.type == 'attributes') { console.log('The ' + mutation.attributeName + ' attribute was modified.'); 
    
         } // Next mutation 
    
        }; // End Function callback 
    
        // Options for the observer (which mutations to observe) 
        let config = { attributes: false, childList: true, subtree: true }; 
    
        // Create an observer instance linked to the callback function 
        let observer = new MutationObserver(callback); 
    
        // Start observing the target node for configured mutations 
        observer.observe(nodeToObserve, config); 
    } // End Function subscribeEvent 
    

    जावास्क्रिप्ट:

    /// attach an event handler, now or in the future, 
        /// for all elements which match childselector, 
        /// within the child tree of the element maching parentSelector. 
        function subscribeEvent(parentSelector, eventName, childSelector, eventCallback) { 
         if (parentSelector == null) 
          throw new ReferenceError("Parameter parentSelector is NULL"); 
         if (childSelector == null) 
          throw new ReferenceError("Parameter childSelector is NULL"); 
         // nodeToObserve: the node that will be observed for mutations 
         var nodeToObserve = parentSelector; 
         if (typeof (parentSelector) === 'string') 
          nodeToObserve = document.querySelector(parentSelector); 
         var eligibleChildren = nodeToObserve.querySelectorAll(childSelector); 
         for (var i = 0; i < eligibleChildren.length; ++i) { 
          eligibleChildren[i].addEventListener(eventName, eventCallback, false); 
         } // Next i 
         // https://stackoverflow.com/questions/2712136/how-do-i-make-this-loop-all-children-recursively 
         function allDescendants(node) { 
          if (node == null) 
           return; 
          for (var i = 0; i < node.childNodes.length; i++) { 
           var child = node.childNodes[i]; 
           allDescendants(child); 
          } // Next i 
          // IE 11 Polyfill 
          if (!Element.prototype.matches) 
           Element.prototype.matches = Element.prototype.msMatchesSelector; 
          if (node.matches) { 
           if (node.matches(childSelector)) { 
            // console.log("match"); 
            node.addEventListener(eventName, eventCallback, false); 
           } // End if ((<Element>node).matches(childSelector)) 
           // else console.log("no match"); 
          } // End if ((<Element>node).matches) 
          // else console.log("no matchfunction"); 
         } // End Function allDescendants 
         // Callback function to execute when mutations are observed 
         var callback = function (mutationsList, observer) { 
          for (var _i = 0, mutationsList_1 = mutationsList; _i < mutationsList_1.length; _i++) { 
           var mutation = mutationsList_1[_i]; 
           // console.log("mutation.type", mutation.type); 
           // console.log("mutation", mutation); 
           if (mutation.type == 'childList') { 
            for (var i = 0; i < mutation.addedNodes.length; ++i) { 
             var thisNode = mutation.addedNodes[i]; 
             allDescendants(thisNode); 
            } // Next i 
           } // End if (mutation.type == 'childList') 
           // else if (mutation.type == 'attributes') { console.log('The ' + mutation.attributeName + ' attribute was modified.'); 
          } // Next mutation 
         }; // End Function callback 
         // Options for the observer (which mutations to observe) 
         var config = { attributes: false, childList: true, subtree: true }; 
         // Create an observer instance linked to the callback function 
         var observer = new MutationObserver(callback); 
         // Start observing the target node for configured mutations 
         observer.observe(nodeToObserve, config); 
        } // End Function subscribeEvent