消息提示

注册成功!

确定 取消
用户名: 密码: 注册
标题:jquery data()源码学习 发帖时间:2017-06-14 10:36:10

乌托
data方法的主要流程:
确定是否有参数传入->
    1.没有参数-> 使用jquery的静态方法  jQuery.data(elem);(elem是调用data()的对象)->返回elem对象的所有cache缓存,如果elem是dom类型且属性没有解析过,则解析elem的属性是否有data-开头的属性,如果有通过dataAttr(elem, name, data[name]);(data[name]的作用:查看是否添加过这个属性,如果有dataAttr直接返回data[name],减少不必要的操作) 得到以data-开头属性对应的值并进行类型转换,之后添加键值对到elem对象的cache缓存;->调用对象elem的缓存
    2.有一个参数->
               (1). 如果参数是对象 ->调用jquery的静态方法jQuery.data( this, key );  //添加到调用对象的缓存 
               (2). 非对象类型的参数-> 调用dataAttr(elem, key, jQuery.data( elem, key ) )// jQuery.data( elem, key )  如果有值代表有缓存,dataAttr会返回这个缓存,如果没有值dataAttr查看调用对象elem的dom属性是否有data-开头的属性,有就返回,没有返回undefined;->返回key的值
    3.有一个以上的参数->jquery的静态方法调用 jQuery.data( this, key, value );


源代码解析:
   1.原生方法 data()
     data: function( key, value ) {
var i, name, data,
      elem = this[0],   //调用对象
        //  attrs =elem? elem.attributes : undefined;
      attrs = elem && elem.attributes;  
       //如果没有参数
      if ( key === undefined ) {        
          //如果有elem对象      
           if ( this.length ) {            
                   // 返回elem对象的所有cache缓存           
                 data = jQuery.data( elem );    
                     //如果是 DOM 元素 && 如果elem对象没有parsedAttrs属性执行html属性data—解析
                 if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
                       i = attrs.length;       // 返回elem对象属性的数量
                       while ( i-- ) {
                              if ( attrs[ i ] ) {    //attrs[i] elem对象属性的第i个键值对
                              name = attrs[ i ].name;    //elem对象属性名
                              //是否存在data-开头的属性
                              if ( name.indexOf( "data-" ) === 0 ) {   
                                           //取到data-后面的属性名,进行一次驼峰命名转换
                                      name = jQuery.camelCase( name.slice(5) );
                                           //通过 dataAttr 解析 elem 元素身上的 html 标签 "data-" 的值
                                       dataAttr( elem, name, data[ name ] );
                              }
                         }
                    }
                     //给elem对象添加parsedAttrs属性,预防多次解析,浪费性能
                   jQuery._data( elem, "parsedAttrs", true );
              }
          }
          return data;
      }

      // 如果key是对象
     if ( typeof key === "object" ) {
            //每个调用对象执行一次
           return this.each(function() {
               //在缓存中储存key对象
           jQuery.data( this, key );
           });
     }
                  //如果参数大于1
     return arguments.length > 1 ?
                 //每个调用对象执行一次
                this.each(function() {
                       //在缓存中储存键值对
                        jQuery.data( this, key, value );
                 }) :
                 //如果参数只有一个&&有调用对象,Query.data( elem, key )  如果有值代表有缓存,dataAttr会返回这个缓存,如果没有值dataAttr查看调用对象elem的dom属性是否有data-开头的属性,有就返回,没有返回undefined;
                  elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined;
}

   2.静态方法 $.data()
         data: function( elem, name, data ) {
return internalData( elem, name, data );
}
   3.函数 internalData()

         function internalData( elem, name, data, pvt  ) {
               //检查 elem 元素是否可以设置数据
if ( !jQuery.acceptData( elem ) ) {
return;
}

var ret, thisCache,
                // 产生jQuery键值随机数 类似于: "11020056177454302087426"
  // jQuery.expando = (core_version + Math.random()).replace(/D/g, "");
  // (core_version + Math.random()) 产生一串随机字符串 "1.10.20.6013481540139765"
   // replace(/D/g, "") 去掉非数字
internalKey = jQuery.expando
        //确定是否是dom元素
isNode = elem.nodeType,
                //是dom元素,取到缓存对象 。如果是 JS 对象,则直接将数据保存在这个对象上,
cache = isNode ? jQuery.cache : elem,
                //elem的internalKey 属性对应全局缓存中的位置
id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;

// 如果是读取数据,且没有数据,则返回
if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
return;
}

if ( !id ) {
if ( isNode ) {
                        // 对于 DOM 结点,jQuery.uuid 会自加 1,并附加到 DOM 元素上
id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
} else {
id = internalKey;
}
}

if ( !cache[ id ] ) {
// 对于 DOM 如果数据缓存对象不存在,则初始化为空对象 {} 
         // 对于 JS 对象,设置方法 toJSON 为空函数,以避免在执行 JSON.stringify() 时暴露缓存数据
         // 如果一个对象定义了方法 toJSON(), JSON.stringify() 在序列化该对象时会调用这个方法来生成该对象的 JSON 元素
cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
}

if ( typeof name === "object" || typeof name === "function" ) {
if ( pvt ) {
cache[ id ] = jQuery.extend( cache[ id ], name );
} else {
cache[ id ].data = jQuery.extend( cache[ id ].data, name );
}
}

thisCache = cache[ id ];

// jQuery data() is stored in a separate object inside the object"s internal data
// cache in order to avoid key collisions between internal data and user-defined
// data.
if ( !pvt ) {
if ( !thisCache.data ) {
thisCache.data = {};
}

thisCache = thisCache.data;
}

if ( data !== undefined ) {
thisCache[ jQuery.camelCase( name ) ] = data;
}

// Check for both converted-to-camel and non-converted data property names
// If a data property was specified
if ( typeof name === "string" ) {

// First Try to find as-is property data
ret = thisCache[ name ];

// Test for null|undefined property data
if ( ret == null ) {

// Try to find the camelCased property
ret = thisCache[ jQuery.camelCase( name ) ];
}
} else {
ret = thisCache;
}

return ret;
}



4.
整个流程中多次使用:
jquery静态方法:  jQuery.data(elem,key,data) ,  函数: dataAttr(elem,key,data)
jQuery.data源代码:
                   data: function( elem, name, data ) {
          return internalData( elem, name, data );
           },
                    
12上一页  第2页,共2页
回复

标题: 回复:jquery data()源码学习

内容:

发贴人: 游客