最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

jQuery中data操作的方法及jQuery的定义

来源:动视网 责编:小采 时间:2020-11-27 19:32:42
文档

jQuery中data操作的方法及jQuery的定义

jQuery中data操作的方法及jQuery的定义:这篇文章给大家介绍的内容是关于jQuery中data操作的方法及jQuery的定义,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。jQuery中有两个关于data操作的方法$().data() $.data(elem);内部其实现均离不开自定义类Data内部类 DataDa
推荐度:
导读jQuery中data操作的方法及jQuery的定义:这篇文章给大家介绍的内容是关于jQuery中data操作的方法及jQuery的定义,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。jQuery中有两个关于data操作的方法$().data() $.data(elem);内部其实现均离不开自定义类Data内部类 DataDa


这篇文章给大家介绍的内容是关于jQuery中data操作的方法及jQuery的定义,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

jQuery中有两个关于data操作的方法

$().data()

$.data(elem);

内部其实现均离不开自定义类Data

内部类 Data

Datasrc/data/Data.js定义,构建时为实例添加expando属性,作为唯一标识

function Data() {
 this.expando = jQuery.expando + Data.uid++;
}

在原型上添加了多个方法

Data.prototype = {
 cache: function(){
 ...
 },
 set: function(){
 ...
 },
 get: function(){
 ...
 },
 access: function(){
 ...
 },
 remove: function(){
 ...
 },
 hasData: function(){
 ...
 }
}

在jq内部,使用cache方法获取缓存的数据。传入一个参数owner,表示要获取缓存数据的对象。判断在owner上是否有expando属性,如果没有,说明这个owner是否第一次调用,需要在其初始化缓存数据对象。判断节点的类型,如果是元素节点或者document节点或者对象时,可以设置缓存数据。如果是元素节点或者document节点,直接使用对象字面量进行赋值,属性名是expando,值为空对象。如果是对象的话,使用Object.defineProperty为其定义数据,属性名也是expando,初始化为{},同时属性描述符可以更改,不可枚举。

Data.prototype.cache

 cache: function( owner ) {

 // Check if the owner object already has a cache
 // 获取在owner的缓存值
 var value = owner[ this.expando ];

 // If not, create one
 if ( !value ) {
 value = {};

 // We can accept data for non-element nodes in modern browsers,
 // but we should not, see #8335.
 // Always return an empty object.
 // 判断owener类型 是否能在其上调用data
 // 在元素节点或body或对象上可以设置data
 // 其他节点不设置缓存数据
 if ( acceptData( owner ) ) {

 // If it is a node unlikely to be stringify-ed or looped over
 // use plain assignment
 // 此处为owner添加属性 key为Data对象的expando值 建立owner和Data对象之间的连接
 // owner是元素节点或body
 if ( owner.nodeType ) {
 owner[ this.expando ] = value;

 // Otherwise secure it in a non-enumerable property
 // configurable must be true to allow the property to be
 // deleted when data is removed
 // owner是对象
 // 为owner添加expando属性 初始化为{},同时属性描述符可以更改,不可枚举
 } else {
 Object.defineProperty( owner, this.expando, {
 value: value,
 configurable: true
 } );
 }
 }
 }

 return value;
 }

使用set来更新缓存对象,分为data(key,value)data(obj)两种调用情况,保存时要将键名保存为驼峰命名法。

Data.prototype.set

 set: function( owner, data, value ) {
 var prop,
 cache = this.cache( owner );

 // Handle: [ owner, key, value ] args
 // Always use camelCase key (gh-2257)
 if ( typeof data === "string" ) {
 cache[ jQuery.camelCase( data ) ] = value;

 // Handle: [ owner, { properties } ] args
 } else {

 // Copy the properties one-by-one to the cache object
 for ( prop in data ) {
 cache[ jQuery.camelCase( prop ) ] = data[ prop ];
 }
 }
 return cache;
 }

使用get来获取缓存对象,调用时有data(key)data()。未指定key时直接返回整个cache对象,否则返回cache[key]。键名也要转为驼峰命名。

Data.prototype.get

 get: function( owner, key ) {
 return key === undefined ?
 this.cache( owner ) :

 // Always use camelCase key (gh-2257)
 owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ];
 }

对调用的方式进行区分,内部调用 setget

通过参数的数量和类型进行区分:

  • key为空时,获取整个cache对象

  • key类型为stringvalue===undefined 对应获取指定值

  • 其他调用均为set,在set内部进行区分

  • Data.prototype.access

     access: function( owner, key, value ) {
    
     // In cases where either:
     //
     // 1. No key was specified
     // 2. A string key was specified, but no value provided
     //
     // Take the "read" path and allow the get method to determine
     // which value to return, respectively either:
     //
     // 1. The entire cache object
     // 2. The data stored at the key
     //
     if ( key === undefined ||
     ( ( key && typeof key === "string" ) && value === undefined ) ) {
    
     return this.get( owner, key );
     }
    
     // When the key is not a string, or both a key and value
     // are specified, set or extend (existing objects) with either:
     //
     // 1. An object of properties
     // 2. A key and value
     //
     this.set( owner, key, value );
    
     // Since the "set" path can have two possible entry points
     // return the expected data based on which path was taken[*]
     return value !== undefined ? value : key;
     }

    使用remove来删除缓存对象属性,调用时,可以传入一个string,表示要删除的键名,或者传入一个保存多个键名的string数组。键名也要转为驼峰命名。如果不传入出参数,则直接删除掉在owner上的缓存数据对象。

    Data.prototype.remove

     remove: function( owner, key ) {
     var i,
     cache = owner[ this.expando ];
    
     if ( cache === undefined ) {
     return;
     }
    
     if ( key !== undefined ) {
    
     // Support array or space separated string of keys
     if ( Array.isArray( key ) ) {
    
     // If key is an array of keys...
     // We always set camelCase keys, so remove that.
     key = key.map( jQuery.camelCase );
     } else {
     key = jQuery.camelCase( key );
    
     // If a key with the spaces exists, use it.
     // Otherwise, create an array by matching non-whitespace
     key = key in cache ?
     [ key ] :
     ( key.match( rnothtmlwhite ) || [] );
     }
    
     i = key.length;
    
     while ( i-- ) {
     delete cache[ key[ i ] ];
     }
     }
    
     // Remove the expando if there's no more data
     if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
    
     // Support: Chrome <=35 - 45
     // Webkit & Blink performance suffers when deleting properties
     // from DOM nodes, so set to undefined instead
     // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
     if ( owner.nodeType ) {
     owner[ this.expando ] = undefined;
     } else {
     delete owner[ this.expando ];
     }
     }
     }

    判断owner上是否有缓存数据。

    Data.prototype.hasData

     hasData: function( owner ) {
     var cache = owner[ this.expando ];
     return cache !== undefined && !jQuery.isEmptyObject( cache );
     }

    jQuery方法的定义

    定义后内部类data后,在/src/data.js进行拓展。在jQuery添加了hasDatadataremoveData_data_removeData等方法,在jQuery.fn上添加了dataremoveData方法。

    在jQuery拓展的方法,都是对Data方法的封装,在调用时$.data()时,并无对setget操作区分,在Data.prototype.access内部区分set和get。下面源码中,dataUserdataPrivData实例,分别为缓存数据和表示jq对象是否将元素的data属性添加到dataUser

    // $.data
    jQuery.extend( {
     hasData: function( elem ) {
     return dataUser.hasData( elem ) || dataPriv.hasData( elem );
     },
    
     data: function( elem, name, data ) {
     return dataUser.access( elem, name, data );
     },
    
     removeData: function( elem, name ) {
     dataUser.remove( elem, name );
     },
    
     // TODO: Now that all calls to _data and _removeData have been replaced
     // with direct calls to dataPriv methods, these can be deprecated.
     _data: function( elem, name, data ) {
     return dataPriv.access( elem, name, data );
     },
    
     _removeData: function( elem, name ) {
     dataPriv.remove( elem, name );
     }
    } );

    jQuery.fn上拓展的方法只有dataremoveData。在data内,先对$().data()$().data({k:v})两个调用情况进行处理。如果是第一种情况,则返回在this[0]上的缓存数据对象,如果是第一次以$().data()的方式调用,同时还会将元素上的data属性添加dataUser中,并更新dataPriv。如果是$().data({k:v})的调用方式,则遍历jq对象,为每个节点更新缓存数据。其他调用方式如$().data(k)$().data(k,v)则调用access进行处理。此处的access并非Data.prototype.access

    removeData则遍历jq对象,删除在每个节点上的缓存数据。

    // $().data
    jQuery.fn.extend( {
     data: function( key, value ) {
     var i, name, data,
     elem = this[ 0 ], // elem为dom对象
     attrs = elem && elem.attributes; // 节点上的属性
    
     // Gets all values
     // $().data()
     if ( key === undefined ) {
     if ( this.length ) {
     data = dataUser.get( elem );
    
     // elem是元素节点,且dataPriv中无hasDataAttrs时执行这个代码块里的代码
     // dataPriv上的hasDataAttrs表示elem是否有data-xxx属性
     // 初始化dataPriv后花括号内的代码不再执行,即以下的if内的代码只执行一次
     if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) {
     i = attrs.length;
     while ( i-- ) {
    
     // Support: IE 11 only
     // The attrs elements can be null (#14894)
     // 将elem的data-*-*属性以*-*转为驼峰命名方式的值为键
     // 在dataAttr函数内保存到dataUser中
     // 所以用$().data可以获取元素的data-*属性 但修改后dom上的属性却不变化
     if ( attrs[ i ] ) {
     name = attrs[ i ].name;
     // name为data-xxx
     if ( name.indexOf( "data-" ) === 0 ) {
     // name为xxx
     name = jQuery.camelCase( name.slice( 5 ) );
     dataAttr( elem, name, data[ name ] );
     }
     }
     }
     // 同时将dataPriv的hasDataAttrs属性设置为真,表示已经将元素属性节点上的data属性保存到缓存对象中
     dataPriv.set( elem, "hasDataAttrs", true );
     }
     }
    
     return data;
     }
     
     // Sets multiple values
     // $().data(obj) 此处遍历this,即遍历jq对象上所有的节点,并在其设置值
     if ( typeof key === "object" ) {
     return this.each( function() {
     dataUser.set( this, key );
     } );
     }
    
     // 除了$().data()和$().data({k:v})的其他情况
     return access( this, function( value ) {
     var data;
    
     // The calling jQuery object (element matches) is not empty
     // (and therefore has an element appears at this[ 0 ]) and the
     // `value` parameter was not undefined. An empty jQuery object
     // will result in `undefined` for elem = this[ 0 ] which will
     // throw an exception if an attempt to read a data cache is made.
     // value undefined说明是获取操作
     // 调用$().data(k)
     if ( elem && value === undefined ) {
    
     // Attempt to get data from the cache
     // The key will always be camelCased in Data
     // 从dataUser中获取 非undefined时返回
     data = dataUser.get( elem, key );
     if ( data !== undefined ) {
     return data;
     }
    
     // Attempt to "discover" the data in
     // HTML5 custom data-* attrs
     // dataUser中不存在key,调用dataAttr查找元素的data-*属性
     // 如果存在属性,更新dataUser并返回其值
     data = dataAttr( elem, key );
     if ( data !== undefined ) {
     return data;
     }
    
     // We tried really hard, but the data doesn't exist.
     return;
     }
    
     // Set the data...
     // jq对象长度 >= 1, 调用如$().data(k,v) 遍历jq对象,为每个节点设置缓存数据
     this.each( function() {
    
     // We always store the camelCased key
     dataUser.set( this, key, value );
     } );
     }, null, value, arguments.length > 1, null, true );
     },
    
     // 遍历jq对象,删除各个元素上的缓存数据
     removeData: function( key ) {
     return this.each( function() {
     dataUser.remove( this, key );
     } );
     }
    } );

    其中,getData用于对元素上的data属性进行类型转换,dataAttr用于获取保存在元素节点上的data属性,并同时更新dataUser。需要注意的是,以$().data(k, v)方式调用时,如果在缓存数据上查找不到属性,则会调用dataAttr在元素查找属性。

    // 属性值是string 进行类型转换
    function getData( data ) {
     if ( data === "true" ) {
     return true;
     }
    
     if ( data === "false" ) {
     return false;
     }
    
     if ( data === "null" ) {
     return null;
     }
    
     // Only convert to a number if it doesn't change the string
     // data转化成number再转成string后仍严格等于data
     if ( data === +data + "" ) {
     return +data;
     }
    
     if ( rbrace.test( data ) ) {
     return JSON.parse( data );
     }
    
     return data;
    }
    
    // 获取元素的dataset中的属性,并保存到dataUser中
    function dataAttr( elem, key, data ) {
     var name;
    
     // If nothing was found internally, try to fetch any
     // data from the HTML5 data-* attribute
     // 此处获取dataset里的值
     if ( data === undefined && elem.nodeType === 1 ) {
     name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); // 此处将驼峰命名方式的key转化为data-*-*
     data = elem.getAttribute( name );
    
     if ( typeof data === "string" ) {
     try {
     data = getData( data );
     } catch ( e ) {}
    
     // Make sure we set the data so it isn't changed later
     // 将元素的data-*属性保存到dataUser中
     dataUser.set( elem, key, data );
     } else {
     data = undefined;
     }
     }
     return data;
    }

    相关文章推荐:

    Angular表单验证的两种方法介绍

    JavaScript函数怎么用?JavaScript函数的属性和方法的介绍

    文档

    jQuery中data操作的方法及jQuery的定义

    jQuery中data操作的方法及jQuery的定义:这篇文章给大家介绍的内容是关于jQuery中data操作的方法及jQuery的定义,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。jQuery中有两个关于data操作的方法$().data() $.data(elem);内部其实现均离不开自定义类Data内部类 DataDa
    推荐度:
    标签: 操作 方法 的方法
    • 热门焦点

    最新推荐

    猜你喜欢

    热门推荐

    专题
    Top