2013-02-27 3 views
11

私は、この関数のソースを見ていないが、私は疑問に思う、それはこのように動作しない:それらへjQuery.on()はどのように機能しますか?

  1. 選択要素(複数可)そのselecotrsによって
  2. 代表提供するイベント・ハンドラを
  3. そのセレクタと常に非委任するにsetIntervalを実行し、すべての

オーバー再委任、その同じイベントまたはこれに純粋なJavaScriptのDOMの説明がありますか?

答えて

15

Event Delegationバージョンの.onについての質問です。

JavaScriptでは、ほとんどのイベントはDOM階層でbubbleです。つまり、ある要素に対してバブル可能なイベントが発生すると、レベルがdocumentまでDOMにバブルアップします。

<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をサポートする予定がない場合を除きます。古いIEでは、addEventListener/attachEventと同様にevent.target || event.srcElementのテスト機能が必要になります。イベントオブジェクトがハンドラ関数に渡されるかグローバルスコープで使用可能になるかをチェックするなどのいくつかの癖があります。ありがたいことに、jQueryはすべてのことをシームレスにバックグラウンドで行います。=]

+0

だけでなく、それはすべてOKですjQueryとjQuery.on()の使い方について、私は興味がありますJavaScriptとDOMだけで同様のスニペットを書くことが可能ですか? –

+0

@Zlatanはい、そうです。そんなことはありませんが、多くの派手な委任セレクタはありません。私は純粋なJSの1つの例を追加します。 –

+0

OK。さて、あなたは 'document.querySelector()'や 'document.querySelectorAll()')を使って例を書くことができると思います: –

2

Necromancing:念の誰で
は/バニラ、JavaScriptで暮らす上でのjQueryを交換する必要があります。

活字体:

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

はJavaScript:

/// 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 
関連する問題