際際滷

際際滷Share a Scribd company logo
EVENTS
A CRASH COURSE
Brian Moschel
@bitovi
http://bitovi.com




                    StealJS
$('button').click(function()
{
  console.log('Hello!');
$('button').click(function()
{
  console.log('Hello!');
DOM LEVEL 0
Embedded in HTML




 <button onclick="alert('hello!');"> Say Hello! </button>
DOM LEVEL 1
Attribute of Element



 document.getElementById('myButton').onclick = function(){
     alert('Hello!');
 }
DOM LEVEL 2
Event Listener



     var el = document.getElementById('myButton')
     el.addEventListener( 'click', function(){
          alert('Hello!');
     }, false);
DEMO
HOW EVENTS TRAVEL

   <html>
  <head>
  </head>
  <body>
    <div id="myDiv">
      <a id="myAnchor"
          href="http://bitovi.com/">bitovi!
      </a>
    </div>
  </body>
</html>
WHAT IS THE BROWSER DOING??
// Specify an event handler for a given event and phase
HTMLNode.prototype.addEventListener =
  function(eventName, handler, phase){
    // Make a __handlers object on
    // this element if there is none already
    if(!this.__handlers){
      this.__handlers = {};
    }

    // If there are no event handler lists for
    // this event, add them
    if(!this.__handlers[eventName]){
      this.__handlers[eventName] =
        {capture : [], bubble: []};
    }

    // Add the new handler function
    // to the specified phase list
    this.__handlers[eventName]
        [phase ? 'capture' : 'bubble'].push(handler);
}
HANDLE()
 1.Event setup
 2.Calculate parent node path
 3.Execute Capture Phase handlers
 4.Execute DOM Level 1 event handler
 5.Execute Bubble Phase handlers
 6.Execute default browser behavior
1. EVENT SETUP
  var elements = [],
  target = ev.target,
  isPropagationStopped = false,
  isDefaultPrevented = false;

// We are on the Capture Phase to start with
ev.eventPhase = 1;

ev.stopPropagation = function(){
  isPropagationStopped = true;
}

ev.preventDefault = function(){
  isDefaultPrevented = true;
}
2. CALCULATE PARENT NODE PATH


    // Loop up through the DOM and collect all of the
  // parent nodes into the 'elements' array
  do{
    elements.push(target);
  }while((target = target.parentNode));

  // Reverse the list so it's a bit easier to read
  // in the following for-loop
  elements.reverse();
3. EXECUTE CAPTURE PHASE HANDLERS
          // For all of the elements in the list...
      for(var i = 0 ; i < elements.length; i++){

          // If stopPropagation() was called, end the loop -
          // we're done.
          if(isPropagationStopped){
            break;
          }

          var currentElement = elements[i],

           //    If there are any event handlers set for
           //    this element, event type and phase,
           //    set that array to 'handlers'. Otherwise,
           //    set 'handlers' to an empty array.
                handlers = currentElement.__handlers
                  && currentElement.__handlers[ev.type]
                  && currentElement.__handlers[ev.type].capture
                  || [];

          ev.currentTarget = currentElement;

          // Loop through the handlers we've collected and
          // execute them in the context of the current element
          for(var h = 0; i < handlers.length; h++){
            handlers[h].call(currentElement, ev);
          }
      }
4. EXECUTE DOM LEVEL 1 EVENT HANDLER



      // If propagation was not stopped, execute
    // the DOM level 1 event handler
    if(!isPropagationStopped){
      ev.target["on" + ev.type].call(ev.target, ev);
    }

    elements.reverse();
    ev.eventPhase = 3;
5. EXECUTE BUBBLE PHASE HANDLERS
    // Basically, do the same thing as before,
 // but with the 'elements' list reversed...
 for(var i = 0 ; i < elements.length; i++){
   if(isPropagationStopped){
     break;
   }

     // ... Also, we are working with the 'bubble' phase
     // this time, not 'capture'
     var currentElement = elements[i],
       handlers = currentElement.__handlers
         && currentElement.__handlers[ev.type]
         && currentElement.__handlers[ev.type].bubble
         || [];

     ev.currentTarget = currentElement;

     for(var h = 0 ; i < handlers.length; h++){
       handlers[h].call(currentElement,ev);
     }
 }
6. EXECUTE DEFAULT BROWSER BEHAVIOR


    // Default behaviors for HTML elements
  if(!isDefaultPrevented){

      // anchor tag (a link)
      if(ev.type == "click"
        && ev.target.nodeName.toLowerCase() == "a"){
        window.location = ev.target.href;
      }

      // default cases for the rest of the elements go here...
  }
DEFAULT ACTIONS

   EVENT                        DEFAULT ACTION
     SUBMIT               SENDS A POST REQUEST WITH FORM DATA


     CLICK         ON AN ANCHOR, SETS WINDOW.LOCATION TO THE ELS href


  MOUSEDOWN                            SELECTS TEXT


 CONTEXTMENU                  OPENS BROWSER CONTEXT MENU


KEYDOWN/KEYPRESS    TEXT IS WRITTEN INTO INPUT OR TAB TO NEXT TABINDEX
EVENT DELEGATION




  $('#todo').on('click', '.delete', function(){
      // delete the todo
  });
EVENT DELEGATION
ADVANTAGES




      1.Performance
      2.Prevent Glue Code
EVENT DATA
bubbles
  Can event bubble?
cancelable
  Can default action be prevented?
currentTarget
  Current element during bubble or capture
eventPhase
  Bubble or capture
target
  The original event target
timestamp
  Time event created
Type
  Name of event
EVENT DATA
MOUSE EVENTS

 altKey/ctrlKey/metaKey/shiftKey
    True if key was pressed
 button
    Which button was pressed?
 clientX/clientY
    x/y relative to browser window
 relatedTarget
    Secondary target (for mouseover its the element entered)
 screenX/screenY
    x/y relative to computer screen
EVENT DATA
KEY EVENTS



 charCode
   Character representation of key pressed
 keyCode
   Numeric key code
STOPPING EVENTS
GOTCHAS
                     PROBLEM                                  $ SOLUTION
IE (8 and below) is almost but not quite exactly unlike
                                                                      $.fn.on
everything shown

Order of dispatching events per element isnt the same
cross browser                                                 jQuery normalizes events


To remove an event, need reference to the original function
                                                                      $.fn.off

Mouseover an internal element causes a mouseout on the
containing element.

                                                              mouseenter/mouseleave
http://bitovi.com/blog/2010/10/a-crash-
course-in-how-dom-events-work.html

More Related Content

Events

  • 5. DOM LEVEL 0 Embedded in HTML <button onclick="alert('hello!');"> Say Hello! </button>
  • 6. DOM LEVEL 1 Attribute of Element document.getElementById('myButton').onclick = function(){ alert('Hello!'); }
  • 7. DOM LEVEL 2 Event Listener var el = document.getElementById('myButton') el.addEventListener( 'click', function(){ alert('Hello!'); }, false);
  • 9. HOW EVENTS TRAVEL <html> <head> </head> <body> <div id="myDiv"> <a id="myAnchor" href="http://bitovi.com/">bitovi! </a> </div> </body> </html>
  • 10. WHAT IS THE BROWSER DOING??
  • 11. // Specify an event handler for a given event and phase HTMLNode.prototype.addEventListener = function(eventName, handler, phase){ // Make a __handlers object on // this element if there is none already if(!this.__handlers){ this.__handlers = {}; } // If there are no event handler lists for // this event, add them if(!this.__handlers[eventName]){ this.__handlers[eventName] = {capture : [], bubble: []}; } // Add the new handler function // to the specified phase list this.__handlers[eventName] [phase ? 'capture' : 'bubble'].push(handler); }
  • 12. HANDLE() 1.Event setup 2.Calculate parent node path 3.Execute Capture Phase handlers 4.Execute DOM Level 1 event handler 5.Execute Bubble Phase handlers 6.Execute default browser behavior
  • 13. 1. EVENT SETUP var elements = [], target = ev.target, isPropagationStopped = false, isDefaultPrevented = false; // We are on the Capture Phase to start with ev.eventPhase = 1; ev.stopPropagation = function(){ isPropagationStopped = true; } ev.preventDefault = function(){ isDefaultPrevented = true; }
  • 14. 2. CALCULATE PARENT NODE PATH // Loop up through the DOM and collect all of the // parent nodes into the 'elements' array do{ elements.push(target); }while((target = target.parentNode)); // Reverse the list so it's a bit easier to read // in the following for-loop elements.reverse();
  • 15. 3. EXECUTE CAPTURE PHASE HANDLERS // For all of the elements in the list... for(var i = 0 ; i < elements.length; i++){ // If stopPropagation() was called, end the loop - // we're done. if(isPropagationStopped){ break; } var currentElement = elements[i], // If there are any event handlers set for // this element, event type and phase, // set that array to 'handlers'. Otherwise, // set 'handlers' to an empty array. handlers = currentElement.__handlers && currentElement.__handlers[ev.type] && currentElement.__handlers[ev.type].capture || []; ev.currentTarget = currentElement; // Loop through the handlers we've collected and // execute them in the context of the current element for(var h = 0; i < handlers.length; h++){ handlers[h].call(currentElement, ev); } }
  • 16. 4. EXECUTE DOM LEVEL 1 EVENT HANDLER // If propagation was not stopped, execute // the DOM level 1 event handler if(!isPropagationStopped){ ev.target["on" + ev.type].call(ev.target, ev); } elements.reverse(); ev.eventPhase = 3;
  • 17. 5. EXECUTE BUBBLE PHASE HANDLERS // Basically, do the same thing as before, // but with the 'elements' list reversed... for(var i = 0 ; i < elements.length; i++){ if(isPropagationStopped){ break; } // ... Also, we are working with the 'bubble' phase // this time, not 'capture' var currentElement = elements[i], handlers = currentElement.__handlers && currentElement.__handlers[ev.type] && currentElement.__handlers[ev.type].bubble || []; ev.currentTarget = currentElement; for(var h = 0 ; i < handlers.length; h++){ handlers[h].call(currentElement,ev); } }
  • 18. 6. EXECUTE DEFAULT BROWSER BEHAVIOR // Default behaviors for HTML elements if(!isDefaultPrevented){ // anchor tag (a link) if(ev.type == "click" && ev.target.nodeName.toLowerCase() == "a"){ window.location = ev.target.href; } // default cases for the rest of the elements go here... }
  • 19. DEFAULT ACTIONS EVENT DEFAULT ACTION SUBMIT SENDS A POST REQUEST WITH FORM DATA CLICK ON AN ANCHOR, SETS WINDOW.LOCATION TO THE ELS href MOUSEDOWN SELECTS TEXT CONTEXTMENU OPENS BROWSER CONTEXT MENU KEYDOWN/KEYPRESS TEXT IS WRITTEN INTO INPUT OR TAB TO NEXT TABINDEX
  • 20. EVENT DELEGATION $('#todo').on('click', '.delete', function(){ // delete the todo });
  • 21. EVENT DELEGATION ADVANTAGES 1.Performance 2.Prevent Glue Code
  • 22. EVENT DATA bubbles Can event bubble? cancelable Can default action be prevented? currentTarget Current element during bubble or capture eventPhase Bubble or capture target The original event target timestamp Time event created Type Name of event
  • 23. EVENT DATA MOUSE EVENTS altKey/ctrlKey/metaKey/shiftKey True if key was pressed button Which button was pressed? clientX/clientY x/y relative to browser window relatedTarget Secondary target (for mouseover its the element entered) screenX/screenY x/y relative to computer screen
  • 24. EVENT DATA KEY EVENTS charCode Character representation of key pressed keyCode Numeric key code
  • 26. GOTCHAS PROBLEM $ SOLUTION IE (8 and below) is almost but not quite exactly unlike $.fn.on everything shown Order of dispatching events per element isnt the same cross browser jQuery normalizes events To remove an event, need reference to the original function $.fn.off Mouseover an internal element causes a mouseout on the containing element. mouseenter/mouseleave

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n