jQuery Data Manipulate API - A source code dissecting journey

deanyan 49 views 36 slides Jan 09, 2020
Slide 1
Slide 1 of 36
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36

About This Presentation

Represent major data manipulate API in jQuery 1.6; such as .data(), removeData(), index(), globalEval() and so no. Also, HTML5 data-* attributes. I will walk you through with diving into jQuery source code and find out the killing techniques used in jQuery.


Slide Content

jQuery Data Manipulate A source code dissecting journey Huiyi Yan

HTML5 data-* Attributes < li  class = "user"  data-name = "John Resig"  data-city = "Boston" data-lang = "js"  data-food = "Bacon" >     < b >John says:</ b > < span >Hello, how are you?</ span > </ li > var  user  =  document . getElementsByTagName ( "li" )[ ]; var  pos  =  ,  span  =  user . getElementsByTagName ( "span" )[ ]; var  phrases  = [   { name :  "city" ,  prefix :  "I am from " },   { name :  "food" ,  prefix :  "I like to eat " },   { name :  "lang" ,  prefix :  "I like to program in " } ]; user . addEventListener (  "click" ,  function (){    var  phrase  =  phrases [  pos ++ ];    // Use the .dataset property    span . innerHTML  =  phrase . prefix  +  user . dataset [  phrase . name  ]; },  false ); REF> http://ejohn.org/blog/html-5-data-attributes/

HTML5 data-* Attributes span . innerHTML  =  phrase . prefix  +    user . getAttribute ( "data-"  +  phrase . name  ) The .dataset property behaves very similarly to the the .attributes property (but it only works as a map of key-value pairs)

HTML5 data-* Attributes While I firmly believe that useful data should be made visible to users, there are circumstances where data-* attributes make sense. For instance, including data-lat and data-lng attributes in an element containing a street address would allow for easily adding markers to a Google Map on the page: < span data-lat = "38.8951"  data-lng = "-77.0363" >     1600 Pennsylvania Ave.     Washington, DC </ span > “ ” REF> http://www.viget.com/inspire/extending-paul-irishs-comprehensive-dom-ready-execution/

HTML5 data-* Attributes Taking a step back, we can use data-* attributes on the body element to provide an indication of where we are within an application: < body  data-controller = "<%= controller_name %>"  data-action = "<%= action_name %>" >  < body  data-controller = "users"  data-action = "show" > The above code will yield something like: REF> http://www.viget.com/inspire/extending-paul-irishs-comprehensive-dom-ready-execution/

.data()/jQuery.data() .data( key, value ) .data( key, value ) .data( obj ) .data( key ) .data( key ) .data()

.data()/jQuery.data() < div >     The values stored were      < span ></ span >     and     < span ></ span > </ div > $ ( "div" ). data ( "test" , {  first :  16 ,  last :  "pizza!"  }); $ ( "span:first" ). text ( $ ( "div" ). data ( "test" ). first ); $ ( "span:last" ). text ( $ ( "div" ). data ( "test" ). last ); < div  data-role = "page"  data-last-value = "43"  data-hidden = "true"  data-options = '{"name":"John"}' ></ div > $ ( "div" ). data ( "role" ) ===  "page" ; $ ( "div" ). data ( "lastValue" ) ===  43 ; $ ( "div" ). data ( "hidden" ) ===  true ; $ ( "div" ). data ( "options" ). name  ===  "John" ;

.data()/jQuery.data() var  myObj  = {}; $ ( myObj ). data ( "city" ,  "Springfield" ); myObj . city  =  "Springfield" var  progressBar  = {}; $ ( progressBar ). bind ( 'setData' ,  function ( e ,  key ,  value ) {      switch  ( key ) {      case  "percent" :          $ ( "#progress" ). width ( value  +  "%" );          $ ( "#percentText" ). text ( value  +  "%" );          break ;      case  "color" :          $ ( "#progress" ). css ( "color" ,  value );          break ;      case  "enabled" :          $ ( '#progress' ). toggleClass ( "active" ,  value );          break ;     } }); $ ( progressBar ). data ( "enabled" ,  true ). data ( "percent" ,  21 ). data ( "color" , "green" ); // You also have easy access to the current values: console . log ( progressBar . enabled );  // true

.data()/jQuery.data() getData  – triggered before data is read from the object. changeData  – triggered whenever data is set or changed. It is used in the  jQuery datalink plugin  .

. removeData()/ jQuery.removeData() .removeData( [ name ] ) < div >value1 before creation: < span ></ span ></ div > < div >value1 after creation: < span ></ span ></ div > < div >value1 after removal: < span ></ span ></ div > $ ( "span:eq(0)" ). text ( ""  +  $ ( "div" ). data ( "test1" )); $ ( "div" ). data ( "test1" ,  "VALUE-1" ); $ ( "div" ). data ( "test2" ,  "VALUE-2" ); $ ( "span:eq(1)" ). text ( ""  +  $ ( "div" ). data ( "test1" )); $ ( "div" ). removeData ( "test1" ); $ ( "span:eq(2)" ). text ( ""  +  $ ( "div" ). data ( "test1" )); $ ( "span:eq(3)" ). text ( ""  +  $ ( "div" ). data ( "test2" ));

jQuery.hasData() jQuery.hasData( element ) The primary advantage of jQuery.hasData(element) is that it does not create and associate a data object with the element if none currently exists. In contrast, jQuery.data(element) always returns a data object to the caller, creating one if no data object previously existed. “ ”

jQuery.hasData() $ ( function (){    var  $p  =  jQuery ( "p" ),  p  =  $p [ ];    $p . append ( jQuery . hasData ( p )+ " " );  /* false */    jQuery . data ( p ,  "testing" ,  123 );    $p . append ( jQuery . hasData ( p )+ " " );  /* true*/    jQuery . removeData ( p ,  "testing" );    $p . append ( jQuery . hasData ( p )+ " " );  /* false */ });

Utilities jQuery.isEmptyObject() jQuery.trim() jQuery.isFunction() jQuery.each() jQuery.globalEval() jQuery.merge() jQuery.proxy() jQuery.extend()

Utilities // Populate the class2type map jQuery . each ( "Boolean Number String Function Array Date RegExp Object" . split ( " " ),  function ( i ,  name ) {      class2type [ "[object "  +  name  +  "]" ] = name . toLowerCase (); }); type :  function ( obj ) {      return  obj  ==  null  ?  String ( obj ) : class2type [ toString . call ( obj )] ||  "object" ; }, // See test/unit/core.js for details concerning isFunction. // Since version 1.3, DOM methods and functions like alert // aren't supported. They return false on IE (#2968). isFunction :  function ( obj ) {      return  jQuery . type ( obj ) ===  "function" ; }, jQuery.isFunction()

Utilities // Use native String.trim function wherever possible trim :  trim  ? function ( text ) {      return  text  ==  null  ?  ""  :  trim . call ( text ); } : // Otherwise use our own trimming functionality function ( text ) {      return  text  ==  null  ?  ""  : text . toString (). replace ( trimLeft , "" ) . replace ( trimRight ,  "" ); }, jQuery.trim()

Utilities isEmptyObject :  function ( obj ) {      for  ( var  name  in  obj ) {          return  false ;     }      return  true ; }, jQuery.isEmptyObject()

Utilities isPlainObject :  function ( obj ) {      // Must be an Object.      // Because of IE, we also have to check the presence of the constructor property.      // Make sure that DOM nodes and window objects don't pass through, as well      if  (! obj  ||  jQuery . type ( obj ) !==  "object"  || obj . nodeType  ||  jQuery . isWindow ( obj )) {          return  false ;     }      // Not own constructor property must be Object      if  ( obj . constructor  && ! hasOwn . call ( obj , "constructor" )  &&! hasOwn . call ( obj . constructor . prototype , "isPrototypeOf" )) {          return  false ;     }      // Own properties are enumerated firstly, so to speed up,      // if last one is own, then all properties are own.      var  key ;      for  ( key  in  obj ) {}      return  key  ===  undefined  ||  hasOwn . call ( obj , key ); }, jQuery.isPlainObject()

Utilities globalEval :  function ( data ) {      if  ( data  &&  rnotwhite . test ( data )) {          // We use execScript on Internet Explorer          // We use an anonymous function so that context is window          // rather than jQuery in Firefox         ( window . execScript  ||          function ( data ) {              window [ "eval" ]. call ( window ,  data );         })( data );     } }, jQuery.globalEval()

Utilities // Bind a function to a context, optionally partially applying any // arguments. proxy :  function ( fn ,  context ) {      if  ( typeof  context  ===  "string" ) {          var  tmp  =  fn [ context ];          context  =  fn ;          fn  =  tmp ;     }      // Quick check to determine if target is callable, in the spec      // this throws a TypeError, but we will just return undefined.      if  (! jQuery . isFunction ( fn )) {          return  undefined ;     }      // Simulated bind      var  args  =  slice . call ( arguments ,  2 ),          proxy  =  function () {              return  fn . apply ( context , args . concat ( slice . call ( arguments )));         };      // Set the guid of unique handler to the same of original handler, so it can be removed      proxy . guid  =  fn . guid  =  fn . guid  ||  proxy . guid  || jQuery . guid ++;      return  proxy ; }, jQuery.proxy()

Utilities jQuery.each() // args is for internal usage only each :  function ( object ,  callback ,  args ) {      var  name ,  i  =  ,          length  =  object . length ,          isObj  =  length  ===  undefined  ||  jQuery . isFunction ( object );      if  ( args ) {          if  ( isObj ) {              for  ( name  in  object ) {                  if  ( callback . apply ( object [ name ],  args ) ===  false ) {                      break ;                 }             }         }  else  {              for  (;  i  <  length ;) {                  if  ( callback . apply ( object [ i ++],  args ) ===  false ) {                      break ;                 }             }         }

Utilities jQuery.each()        // A special, fast, case for the most common use of each     }  else  {          if  ( isObj ) {              for  ( name  in  object ) {                  if  ( callback . call ( object [ name ],  name ,  object [ name ]) === false ) {                      break ;                 }             }         }  else  {              for  (;  i  <  length ;) {                  if  ( callback . call ( object [ i ],  i ,  object [ i ++]) ===  false ) {                      break ;                 }             }         }     }      return  object ; },

Miscellaneous .index() .map() .get() .toArray() .slice()

Miscellaneous .index() .index( selector ) selector A selector representing a jQuery collection in which to look for an element. .index( element ) element The DOM element or first element within the jQuery object to look for.

Miscellaneous < span >Click a div!</ span > < div >First div</ div > < div >Second div</ div > < div >Third div</ div > < script >     $("div").click(function () {         // this is the dom element clicked         var index = $("div").index(this);         $("span").text("That was div index #" + index);     }); </ script > .index() On click, returns the index (based zero) of that div in the page.

Miscellaneous < ul >     < li  id = "foo" >foo</ li >     < li  id = "bar" >bar</ li >     < li  id = "baz" >baz</ li > </ ul > < div ></ div > < script >$('div').html('Index: ' +  $('#bar').index('li') );</ script > .index() Returns the index for the element with ID bar in relation to all <li> elements.

Miscellaneous toArray :  function ()  {      return  slice . call ( this ,  ); } Reversed - < span ></ span > < div >One</ div > < div >Two</ div > < div >Three</ div > < script > function  disp ( divs ) {      var  a  = [];      for  ( var  i  =  ;  i  <  divs . length ;  i ++) {          a . push ( divs [ i ]. innerHTML );     }      $ ( "span" ). text ( a . join ( " " )); } disp ( $ ( "div" ). toArray (). reverse ()); </ script > toArray()

Miscellaneous .map() .map( callback(index, domElement) ) callback(index, domElement) A function object that will be invoked for each element in the current set.

Miscellaneous < input  type = "button"  value = "equalize div heights" > < div  style = "background:red; height: 40px; " ></ div > < div  style = "background:green; height: 70px;" ></ div > < div  style = "background:blue; height: 50px; " ></ div > < script >     $.fn.equalizeHeights = function(){      return this.height( Math.max.apply(this, $(this).map(function(i,e){ return $(e).height() }).get() ) )     }     $('input').click(function(){      $('div').equalizeHeights();     }); </ script > .map() Equalize the heights of the divs.

Miscellaneous map :  function ( callback ) {      return  this . pushStack ( jQuery . map ( this ,  function ( elem ,  i ) {          return  callback . call ( elem ,  i ,  elem );     })); }, .map()

Miscellaneous // arg is for internal usage only map :  function ( elems ,  callback ,  arg ) {      var  value ,  key ,  ret  = [],          i  =  ,          length  =  elems . length ,          // jquery objects are treated as arrays          isArray  =  elems  instanceof  jQuery  ||  length  !==  undefined  && typeof  length  ===  "number"  && (( length  >  0  &&  elems [ ] &&  elems [ length  - 1 ]) ||  length  ===  0  ||  jQuery . isArray ( elems ));      // Go through the array, translating each of the items to their      if  ( isArray ) {          for  (;  i  <  length ;  i ++) {              value  =  callback ( elems [ i ],  i ,  arg );              if  ( value  !=  null ) {                  ret [ ret . length ] =  value ;             }         }          // Go through every key on the object,     }  else  {          for  ( key  in  elems ) {              value  =  callback ( elems [ key ],  key ,  arg );              if  ( value  !=  null ) {                  ret [ ret . length ] =  value ;             }         }     }      // Flatten any nested arrays      return  ret . concat . apply ([],  ret ); }, .map()

Miscellaneous // Take an array of elements and push it onto the stack // (returning the new matched element set) pushStack :  function ( elems ,  name ,  selector ) {      // Build a new jQuery matched element set      var  ret  =  this . constructor ();      if  ( jQuery . isArray ( elems )) {          push . apply ( ret ,  elems );     }  else  {          jQuery . merge ( ret ,  elems );     }      // Add the old object onto the stack (as a reference)      ret . prevObject  =  this ;      ret . context  =  this . context ;      if  ( name  ===  "find" ) {          ret . selector  =  this . selector  + ( this . selector  ?  " "  :  "" ) + selector ;     }  else if  ( name ) {          ret . selector  =  this . selector  +  "."  +  name  +  "("  +  selector  + ")" ;     }      // Return the newly-formed element set      return  ret ; }, .map()

Miscellaneous // Determine the position of an element within // the matched set of elements index :  function ( elem ) {      if  (! elem  ||  typeof  elem  ===  "string" ) {          return  jQuery . inArray ( this [ ],          // If it receives a string, the selector is used          // If it receives nothing, the siblings are used          elem  ?  jQuery ( elem ) :  this . parent (). children ());     }      // Locate the position of the desired element      return  jQuery . inArray (      // If it receives a jQuery object, the first element is used      elem . jquery  ?  elem [ ] :  elem ,  this ); }, .index()

Miscellaneous // Get the Nth element in the matched element set OR // Get the whole matched element set as a clean array get :  function ( num ) {      return  num  ==  null  ?      // Return a 'clean' array      this . toArray () :      // Return just the object     ( num  <  0  ?  this [ this . length  +  num ] :  this [ num ]); }, .get()

General Attributes .attr() .removeAttr() .prop() .removeProp()

General Attributes attr :  function ( name ,  value ) {      return  jQuery . access ( this ,  name ,  value ,  true ,  jQuery . attr ); }, removeAttr :  function ( name ) {      return  this . each ( function () {          jQuery . removeAttr ( this ,  name );     }); }, .attr() .removeAttr ()

General Attributes prop :  function ( name ,  value ) {      return  jQuery . access ( this ,  name ,  value ,  true ,  jQuery . prop ); }, removeProp :  function ( name ) {      return  this . each ( function () {          // try/catch handles cases where IE balks (such as removing a property on window)          try  {              this [ name ] =  undefined ;              delete  this [ name ];         }  catch  ( e ) {}     }); }, .prop() .removeProp()