一、实现原理:
对于DOM元素,通过分配一个唯一的关联id把DOM元素和该DOM元素的数据缓存对象关联起来,关联id被附加到以jQuery.expando的值命名的属性上,数据存储在全局缓存对象jQuery.cache中。在读取、设置、移除数据时,将通过关联id从全局缓存对象jQuery.cache中找到关联的数据缓存对象,然后在数据缓存对象上执行读取、设置、移除操作。
对于Javascript对象,数据则直接存储在该Javascript对象的属性jQuery.expando上。在读取、设置、移除数据时,实际上是对Javascript对象的数据缓存对象执行读取、设置、移除操作。
为了避免jQuery内部使用的数据和用户自定义的数据发生冲突,数据缓存模块把内部数据存储在数据缓存对象上,把自定义数据存储在数据缓存对象的属性data上。
二、总体结构:
// 数据缓存 Data
jQuery.extend({
// 全局缓存对象
cache: {},
// 唯一 id种子
uuid:0,
// 页面中每个jQuery副本的唯一标识
expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
// 是否有关联的数据
hasData: function(){},
// 设置、读取自定数据或内部数据
data: function(elem, name, data, pvt) {},
// 移除自定义数据或内部数据
removeData: function(elem, name, pvt) {},
// 设置、读取内部数据
_data: function(elem, name, data) {},
// 是否可以设置数据
acceptData: function(elem){}
});
jQuery.fn.extend({
// 设置、读取自定义数据,解析HTML5属性data-
data: function(key,value){},
// 移除自定义数据
removeData: function(key){}
});
// 解析HTML5属性 data-
function dataAttr(elem,key,data){}
// 检查数据缓存对象是否为空
function isEmptyDataObject(obj){}
jQuery.extend({
// 清空数据缓存对象
cleanData: function(elems){}
});
三、$.data(elem, name, data), $.data(elem, name)
$.data(elem, name, data)的使用方法:
如果传入参数name, data, 则设置任意类型的数据
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery.data demo</title>
<style>
div {
color: blue;
}
span {
color: red;
}
</style>
<script src="/UploadFiles/2021-04-02/jquery-1.10.2.js">
$.data(elem, name)的使用方法:
如果传入key, 未传入参数data, 则读取并返回指定名称的数据
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery.data demo</title>
<style>
div {
margin: 5px;
background: yellow;
}
button {
margin: 5px;
font-size: 14px;
}
p {
margin: 5px;
color: blue;
}
span {
color: red;
}
</style>
<script src="/UploadFiles/2021-04-02/jquery-1.10.2.js">
$.data(elem, name, data), $.data(elem, name) 源码解析:
jQuery.extend({
// 1. 定义jQuery.data(elem, name, data, pvt)
data: function( elem, name, data, pvt /* Internal Use Only */ ) {
// 2. 检查是否可以设置数据
if ( !jQuery.acceptData( elem ) ) {
return; // 如果参数elem不支持设置数据,则立即返回
}
// 3 定义局部变量
var privateCache, thisCache, ret,
internalKey = jQuery.expando,
getByName = typeof name === "string",
// We have to handle DOM nodes and JS objects differently because IE6-7
// can't GC object references properly across the DOM-JS boundary
isNode = elem.nodeType, // elem是否是DOM元素
// Only DOM nodes need the global jQuery cache; JS object data is
// attached directly to the object so GC can occur automatically
cache = isNode "events";
// Avoid doing any more work than we need to when trying to get data on an
// object that has no data at all
// 4. 如果是读取数据,但没有数据,则返回
if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
return;
// getByName && data === undefined 如果name是字符串,data是undefined, 说明是在读取数据
// !id || !cache[id] || (!isEvents && !pvt && !cache[id].data 如果关联id不存在,说明没有数据;如果cache[id]不存在,也说明没有数据;如果是读取自动以数据,但cache[id].data不存在,说明没有自定义数据
}
// 5. 如果关联id不存在,则分配一个
if ( !id ) {
// Only DOM nodes need a new unique ID for each element since their data
// ends up in the global cache
if ( isNode ) {
elem[ internalKey ] = id = ++jQuery.uuid; // 对于DOM元素,jQuery.uuid会自动加1,并附加到DOM元素上
} else {
id = internalKey; // 对于javascript对象,关联id就是jQuery.expando
}
}
// 6. 如果数据缓存对象不存在,则初始化为空对象{}
if ( !cache[ id ] ) {
cache[ id ] = {};
// Avoids exposing jQuery metadata on plain JS objects when the object
// is serialized using JSON.stringify
if ( !isNode ) {
cache[ id ].toJSON = jQuery.noop; // 对于javascript对象,设置方法toJSON为空函数,以避免在执行JSON.stringify()时暴露缓存数据。如果一个对象定义了方法toJSON(),JSON.stringify()在序列化该对象时会调用这个方法来生成该对象的JSON元素
}
}
// An object can be passed to jQuery.data instead of a key/value pair; this gets
// shallow copied over onto the existing cache
// 7. 如果参数name是对象或函数,则批量设置数据
if ( typeof name === "object" || typeof name === "function" ) {
if ( pvt ) {
cache[ id ] = jQuery.extend( cache[ id ], name ); // 对于内部数据,把参数name中的属性合并到cache[id]中
} else {
cache[ id ].data = jQuery.extend( cache[ id ].data, name ); // 对于自定义数据,把参数name中的属性合并到cache[id].data中
}
}
// 8. 如果参数data不是undefined, 则设置单个数据
privateCache = 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;
}
// Users should not attempt to inspect the internal events object using jQuery.data,
// it is undocumented and subject to change. But does anyone listen"events",并且未设置过自定义数据"events",则返回事件婚车对象,在其中存储了事件监听函数。
return privateCache.events;
}
// Check for both converted-to-camel and non-converted data property names
// If a data property was specified
//10. 如果参数name是字符串,则读取单个数据
if ( getByName ) {
// First Try to find as-is property data
ret = thisCache[ name ]; // 先尝试读取参数name对应的数据
// Test for null|undefined property data
if ( ret == null ) { // 如果未取到,则把参数name转换为驼峰式再次尝试读取对应的数据
// Try to find the camelCased property
ret = thisCache[ jQuery.camelCase( name ) ];
}
} else { // 11. 如果未传入参数name,data,则返回数据缓存对象
ret = thisCache;
}
return ret;
},
// For internal use only.
_data: function( elem, name, data ) {
return jQuery.data( elem, name, data, true );
},
});
四、.data(key, value), .data(key)
使用方法:
$( "body" ).data( "foo", 52 ); // 传入key, value
$( "body" ).data( "bar", { myType: "test", count: 40 } ); // 传入key, value
$( "body" ).data( { baz: [ 1, 2, 3 ] } ); // 传入key, value
$( "body" ).data( "foo" ); // 52 // 传入key
$( "body" ).data(); // 未传入参数
HTML5 data attriubutes:
<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(key, value), .data(key) 源码解析
jQuery.fn.extend({ // 1. 定义.data(key, value)
data: function( key, value ) {
var parts, attr, name,
data = null;
// 2. 未传入参数的情况
if ( typeof key === "undefined" ) {
if ( this.length ) { // 如果参数key是undefined, 即参数格式是.data(), 则调用方法jQuery.data(elem, name, data, pvt)获取第一个匹配元素关联的自定义数据缓存对象,并返回。
data = jQuery.data( this[0] );
if ( this[0].nodeType === 1 && !jQuery._data( this[0], "parsedAttrs" ) ) {
attr = this[0].attributes;
for ( var i = 0, l = attr.length; i < l; i++ ) {
name = attr[i].name;
if ( name.indexOf( "data-" ) === 0 ) {
name = jQuery.camelCase( name.substring(5) );
dataAttr( this[0], name, data[ name ] );
}
}
jQuery._data( this[0], "parsedAttrs", true );
}
}
return data;
// 3. 参数key 是对象的情况,即参数格式是.data(key),则遍历匹配元素集合,为每个匹配元素调用方法jQuery.data(elem, name, data,pvt)批量设置数据
} else if ( typeof key === "object" ) {
return this.each(function() {
jQuery.data( this, key );
});
}
// 4. 只传入参数key的情况 如果只传入参数key, 即参数格式是.data(key),则返回第一个匹配元素的指定名称数据
parts = key.split(".");
parts[1] = parts[1] "." + parts[1] : "";
if ( value === undefined ) {
data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
// Try to fetch any internally stored data first
if ( data === undefined && this.length ) {
data = jQuery.data( this[0], key );
data = dataAttr( this[0], key, data );
}
return data === undefined && parts[1] "setData" + parts[1] + "!", args );
jQuery.data( this, key, value );
self.triggerHandler( "changeData" + parts[1] + "!", args );
});
}
},
removeData: function( key ) {
return this.each(function() {
jQuery.removeData( this, key );
});
}
});
// 6. 函数dataAttr(elem, key, data)解析HTML5属性data-
function dataAttr( elem, key, data ) {
// If nothing was found internally, try to fetch any
// data from the HTML5 data-* attribute
// 只有参数data为undefined时,才会解析HTML5属性data-
if ( data === undefined && elem.nodeType === 1 ) {
var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
data = elem.getAttribute( name );
if ( typeof data === "string" ) {
try {
data = data === "true" "false" "null" "htmlcode">
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery.removeData demo</title>
<style>
div {
margin: 2px;
color: blue;
}
span {
color: red;
}
</style>
<script src="/UploadFiles/2021-04-02/jquery-1.10.2.js">
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>removeData demo</title>
<style>
div {
margin: 2px;
color: blue;
}
span {
color: red;
}
</style>
<script src="/UploadFiles/2021-04-02/jquery-1.10.2.js">
$.removeData(elem, name),.removeData(key) 源码解析:
$.extend({
// jQuery.removeData(elem,name,pvt)用于移除通过jQuery.data()设置的数据
removeData: function( elem, name, pvt /* Internal Use Only */ ) {
if ( !jQuery.acceptData( elem ) ) {
return;
}
var thisCache, i, l,
// Reference to internal data cache key
internalKey = jQuery.expando,
isNode = elem.nodeType,
// See jQuery.data for more information
cache = isNode " " );
}
}
}
// 遍历参数name中的数据名,用运算符delete逐个从数据缓存对象thisCache中移除
for ( i = 0, l = name.length; i < l; i++ ) {
delete thisCache[ name[i] ];
}
// If there is no data left in the cache, we want to continue
// and let the cache object itself get destroyed
if ( !( pvt "data" && jQuery.isEmptyObject( obj[name] ) ) {
continue;
}
if ( name !== "toJSON" ) {
return false;
}
}
return true;
}
六、$.hasData(elem)
使用方法:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery.hasData demo</title>
<script src="/UploadFiles/2021-04-02/jquery-1.10.2.js">
标签:
jQuery,缓存,$.data
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件!
如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
白云城资源网 Copyright www.dyhadc.com
暂无“jQuery中数据缓存$.data的用法及源码完全解析”评论...
更新日志
- 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]