亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

jQuery中數據緩存$.data的用法及源碼完全解析

2019-11-20 10:11:04
字體:
來源:轉載
供稿:網友

一、實現原理:

對于DOM元素,通過分配一個唯一的關聯id把DOM元素和該DOM元素的數據緩存對象關聯起來,關聯id被附加到以jQuery.expando的值命名的屬性上,數據存儲在全局緩存對象jQuery.cache中。在讀取、設置、移除數據時,將通過關聯id從全局緩存對象jQuery.cache中找到關聯的數據緩存對象,然后在數據緩存對象上執行讀取、設置、移除操作。

對于Javascript對象,數據則直接存儲在該Javascript對象的屬性jQuery.expando上。在讀取、設置、移除數據時,實際上是對Javascript對象的數據緩存對象執行讀取、設置、移除操作。

為了避免jQuery內部使用的數據和用戶自定義的數據發生沖突,數據緩存模塊把內部數據存儲在數據緩存對象上,把自定義數據存儲在數據緩存對象的屬性data上。

二、總體結構:

// 數據緩存 DatajQuery.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="http://code.jquery.com/jquery-1.10.2.js"></script></head><body><div> The values stored were <span></span> and <span></span></div><script>var div = $( "div" )[ 0 ];jQuery.data( div, "test", { first: 16, last: "pizza!"});$( "span:first" ).text( jQuery.data( div, "test" ).first );$( "span:last" ).text( jQuery.data( div, "test" ).last );</script></body></html>

$.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="http://code.jquery.com/jquery-1.10.2.js"></script></head><body><div>A div</div><button>Get "blah" from the div</button><button>Set "blah" to "hello"</button><button>Set "blah" to 86</button><button>Remove "blah" from the div</button><p>The "blah" value of this div is <span>?</span></p><script>$( "button" ).click( function() { var value,  div = $( "div" )[ 0 ]; switch ( $( "button" ).index( this ) ) { case 0 :  value = jQuery.data( div, "blah" );  break; case 1 :  jQuery.data( div, "blah", "hello" );  value = "Stored!";  break; case 2 :  jQuery.data( div, "blah", 86 );  value = "Stored!";  break; case 3 :  jQuery.removeData( div, "blah" );  value = "Removed!";  break; } $( "span" ).text( "" + value );});</script></body></html>


$.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 ? jQuery.cache : elem, // 如果是DOM元素,為了避免javascript和DOM元素之間循環引用導致的瀏覽器(IE6/7)垃圾回收機制不起作用,要把數據存儲在全局緩存對象jQuery.cache中;對于javascript對象,來及回收機制能夠自動發生,不會有內存泄露的問題,因此數據可以查收存儲在javascript對象上   // Only defining an ID for JS objects if its cache already exists allows   // the code to shortcut on the same path as a DOM node with no cache   id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,   isEvents = name === "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? No.  // 9. 特殊處理events   if ( isEvents && !thisCache[ name ] ) { // 如果參數name是字符串"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] ?    this.data( parts[0] ) :    data;  // 5. 傳入參數key和value的情況 即參數格式是.data(key, value),則為每個匹配元素設置任意類型的數據,并觸發自定義事件setData, changeData  } else {   return this.each(function() {    var self = jQuery( this ),     args = [ parts[0], value ];    self.triggerHandler( "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" ? true :    data === "false" ? false :    data === "null" ? null :    jQuery.isNumeric( data ) ? parseFloat( data ) :     rbrace.test( data ) ? jQuery.parseJSON( data ) :     data;   } catch( e ) {}   // Make sure we set the data so it isn't changed later   jQuery.data( elem, key, data );  } else {   data = undefined;  } } return data;}

五、$.removeData(elem, name),.removeData(key)
使用方法:

<!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="http://code.jquery.com/jquery-1.10.2.js"></script></head><body><div>value1 before creation: <span></span></div><div>value1 after creation: <span></span></div><div>value1 after removal: <span></span></div><div>value2 after removal: <span></span></div><script>var div = $( "div" )[ 0 ];$( "span:eq(0)" ).text( "" + $( "div" ).data( "test1" ) ); //undefinedjQuery.data( div, "test1", "VALUE-1" );jQuery.data( div, "test2", "VALUE-2" );$( "span:eq(1)" ).text( "" + jQuery.data( div, "test1" ) ); // VALUE-1jQuery.removeData( div, "test1" );$( "span:eq(2)" ).text( "" + jQuery.data( div, "test1" ) ); // undefined$( "span:eq(3)" ).text( "" + jQuery.data( div, "test2" ) ); // value2</script></body></html>
<!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="http://code.jquery.com/jquery-1.10.2.js"></script></head><body><div>value1 before creation: <span></span></div><div>value1 after creation: <span></span></div><div>value1 after removal: <span></span></div><div>value2 after removal: <span></span></div><script>$( "span:eq(0)" ).text( "" + $( "div" ).data( "test1" ) ); // undefined$( "div" ).data( "test1", "VALUE-1" );$( "div" ).data( "test2", "VALUE-2" );$( "span:eq(1)" ).text( "" + $( "div").data( "test1" ) ); // VALUE-1$( "div" ).removeData( "test1" );$( "span:eq(2)" ).text( "" + $( "div" ).data( "test1" ) ); // undefined$( "span:eq(3)" ).text( "" + $( "div" ).data( "test2" ) ); // VALUE-2</script></body></html>

$.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 ? jQuery.cache : elem,   // See jQuery.data for more information   id = isNode ? elem[ internalKey ] : internalKey;  // If there is already no cache entry for this object, there is no  // purpose in continuing  if ( !cache[ id ] ) {   return;  }    // 如果傳入參數name, 則移除一個或多個數據  if ( name ) {   thisCache = pvt ? cache[ id ] : cache[ id ].data;   if ( thisCache ) { // 只有數據緩存對象thisCache存在時,才有必要移除數據    // Support array or space separated string names for data keys    if ( !jQuery.isArray( name ) ) {     // try the string as a key before any manipulation     if ( name in thisCache ) {      name = [ name ];     } else {      // split the camel cased version by spaces unless a key with the spaces exists      name = jQuery.camelCase( name );      if ( name in thisCache ) {       name = [ name ];      } else {       name = name.split( " " );      }     }    }    // 遍歷參數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 ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {     return;    }   }  }  // See jQuery.data for more information  // 刪除自定義數據緩存對象cache[id].data  if ( !pvt ) {   delete cache[ id ].data;   // Don't destroy the parent cache unless the internal data object   // had been the only thing left in it   if ( !isEmptyDataObject(cache[ id ]) ) {    return;   }  }  // Browsers that fail expando deletion also refuse to delete expandos on  // the window, but it will allow it on all other JS objects; other browsers  // don't care  // Ensure that `cache` is not a window object #10080  // 刪除數據緩存對象cache[id]  if ( jQuery.support.deleteExpando || !cache.setInterval ) {   delete cache[ id ];  } else {   cache[ id ] = null;  }  // We destroyed the cache and need to eliminate the expando on the node to avoid  // false lookups in the cache for entries that no longer exist  // 刪除DOM元素上擴展的jQuery.expando屬性  if ( isNode ) {   // IE does not allow us to delete expando properties from nodes,   // nor does it have a removeAttribute function on Document nodes;   // we must handle all of these cases   if ( jQuery.support.deleteExpando ) {    delete elem[ internalKey ];   } else if ( elem.removeAttribute ) {    elem.removeAttribute( internalKey );   } else {    elem[ internalKey ] = null;   }  } }});jQuery.fn.extend({  removeData: function( key ) {   return this.each(function() {    jQuery.removeData( this, key );   });  }});// checks a cache object for emptinessfunction isEmptyDataObject( obj ) { for ( var name in obj ) {  // if the public data object is empty, the private is still empty  if ( name === "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="http://code.jquery.com/jquery-1.10.2.js"></script></head><body><p>Results: </p><script>var $p = jQuery( "p" ), p = $p[ 0 ];$p.append( jQuery.hasData( p ) + " " ); // false$.data( p, "testing", 123 );$p.append( jQuery.hasData( p ) + " " ); // true$.removeData( p, "testing" );$p.append( jQuery.hasData( p ) + " " ); // false$p.on( "click", function() {} );$p.append( jQuery.hasData( p ) + " " ); // true$p.off( "click" );$p.append( jQuery.hasData( p ) + " " ); // false</script></body></html>$.hasData(elem) 源碼解析:$.extend({  hasData: function( elem ) {   elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];   return !!elem && !isEmptyDataObject( elem );   // 如果關聯的數據緩存對象存在,并且含有數據,則返回true, 否則返回false。 這里用兩個邏輯非運算符! 把變量elem轉換為布爾值 }});

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲精品成人久久久| 欧美精品在线免费播放| 亚洲欧美激情另类校园| 国产精品久久久久av| 国产日本欧美一区二区三区在线| 日韩中文字幕在线精品| 日本精品久久久| 欧美成人在线免费视频| 欧美激情精品久久久久久大尺度| 91久久久久久国产精品| 日韩美女在线观看| 欧洲亚洲女同hd| 欧美电影在线观看网站| 91精品国产综合久久香蕉922| 亚洲精品乱码久久久久久金桔影视| 国产精品国语对白| 日韩亚洲欧美中文高清在线| 免费av一区二区| 欧美激情亚洲综合一区| 亚洲专区中文字幕| 欧美一级片一区| 亚洲国产成人在线视频| 91九色视频在线| 国产亚洲欧美日韩美女| 欧美自拍视频在线观看| 国产在线拍揄自揄视频不卡99| 一区二区在线免费视频| 68精品国产免费久久久久久婷婷| 亚洲视频在线观看视频| 午夜精品久久17c| 这里精品视频免费| 亚洲aⅴ男人的天堂在线观看| 亚洲美女在线观看| 国产精品自拍小视频| 亚洲成**性毛茸茸| 色婷婷av一区二区三区久久| 亚洲一区二区三区在线免费观看| 亚洲国产精品99久久| 91产国在线观看动作片喷水| 国产精品人人做人人爽| 欧美做爰性生交视频| 精品久久久999| 国产精品久久电影观看| 91亚洲精品视频| 欧美精品videos| 亚洲精品日韩在线| 91精品啪aⅴ在线观看国产| 国内精品伊人久久| xxx成人少妇69| 91黑丝在线观看| 欧美中文字幕在线视频| 国产精品成人观看视频国产奇米| 欧美国产精品人人做人人爱| 亚洲国产欧美在线成人app| 日韩免费看的电影电视剧大全| 欧美巨乳在线观看| 91在线色戒在线| 国产亚洲精品久久久久动| 久久久久久69| 国产精品91久久久久久| 人九九综合九九宗合| 92裸体在线视频网站| 欧美黑人性视频| 超碰日本道色综合久久综合| 亚洲人成电影网站| 久久久久久69| 亚洲自拍偷拍一区| 精品国产一区二区三区久久狼5月| 日韩电影中文字幕av| 日韩中文字幕久久| 亚洲国产欧美一区二区三区同亚洲| 国产91久久婷婷一区二区| 中文字幕视频一区二区在线有码| 亚洲成人激情小说| 91在线无精精品一区二区| 自拍视频国产精品| 国产日本欧美一区二区三区在线| 欧美精品在线观看91| 69av视频在线播放| 亚洲欧美日韩天堂一区二区| 亚洲综合精品伊人久久| 国产国产精品人在线视| 亚洲自拍av在线| 精品久久在线播放| 91av国产在线| 国产精品视频内| 欧美大成色www永久网站婷| 国产精品三级网站| 国产乱肥老妇国产一区二| 日本人成精品视频在线| 欧美黄色片在线观看| 91老司机精品视频| 欧美又大粗又爽又黄大片视频| 国产精品中文久久久久久久| 亚洲免费视频一区二区| 在线激情影院一区| 亚洲欧美日韩区| 亚洲国产精品悠悠久久琪琪| 色噜噜久久综合伊人一本| 亚洲精品视频免费在线观看| 日韩精品高清在线观看| 三级精品视频久久久久| 欧洲亚洲妇女av| 亚洲影影院av| 亚洲伦理中文字幕| 成人黄色影片在线| 亚洲高清福利视频| 国产精品自产拍在线观看中文| 日韩成人激情在线| 日韩免费观看在线观看| 久久久久成人精品| 91久久久在线| 日韩男女性生活视频| 国产午夜精品麻豆| 亚洲性猛交xxxxwww| 97色在线视频| 欧美激情精品久久久久久变态| 亚洲国产精品va在线观看黑人| 亚洲欧美日韩中文在线制服| 久久亚洲影音av资源网| 91av网站在线播放| 高清欧美电影在线| 欧美日韩一区二区在线| 夜夜嗨av一区二区三区免费区| 亚洲人成毛片在线播放| 亚洲变态欧美另类捆绑| 日韩高清免费观看| 亚洲精品国产精品乱码不99按摩| 国产精品视频自拍| 欧美性极品少妇精品网站| 91午夜理伦私人影院| 久热99视频在线观看| 欧美精品久久久久久久久| 色妞色视频一区二区三区四区| 日韩视频精品在线| 欧美一级片一区| 日本成人激情视频| 国产有码一区二区| 久久97久久97精品免视看| 欧美天天综合色影久久精品| 美女av一区二区三区| 亚洲人高潮女人毛茸茸| 日韩精品在线看| 亚洲网址你懂得| 欧美日韩国产在线播放| 亚洲区中文字幕| 欧美肥臀大乳一区二区免费视频| 91香蕉嫩草神马影院在线观看| 日韩免费观看网站| 色综合天天狠天天透天天伊人| 成人乱人伦精品视频在线观看| 成人做爰www免费看视频网站| 国产精品视频专区| 国产一区二中文字幕在线看| 欧美老女人在线视频| 国产精品一区二区电影| 欧美美女18p| 九九久久久久久久久激情| 国产精品永久免费| 九色精品美女在线| 国产91在线播放精品91| 亚洲激情小视频| 欧美亚洲伦理www| 91精品一区二区|