中文字幕免费精品_亚洲视频自拍_亚洲综合国产激情另类一区_色综合咪咪久久

jQuery中數據緩存$.data的用法及源碼完全解析
來源:易賢網 閱讀:1079 次 日期:2016-07-06 11:34:30
溫馨提示:易賢網小編為您整理了“jQuery中數據緩存$.data的用法及源碼完全解析”,方便廣大網友查閱!

這篇文章主要介紹了jQuery中的數據緩存$.data的用法及源碼完全解析,深入解讀了jQuery對緩存對象的讀寫和移除的實現,需要的朋友可以參考下

一、實現原理:

對于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="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" ) ); //undefined

jQuery.data( div, "test1", "VALUE-1" );

jQuery.data( div, "test2", "VALUE-2" );

$( "span:eq(1)" ).text( "" + jQuery.data( div, "test1" ) ); // VALUE-1

jQuery.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 emptiness

function 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轉換為布爾值

 }

});

更多信息請查看網絡編程
由于各方面情況的不斷調整與變化,易賢網提供的所有考試信息和咨詢回復僅供參考,敬請考生以權威部門公布的正式信息和咨詢為準!

2026上岸·考公考編培訓報班

  • 報班類型
  • 姓名
  • 手機號
  • 驗證碼
關于我們 | 聯系我們 | 人才招聘 | 網站聲明 | 網站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 新媒體/短視頻平臺 | 手機站點 | 投訴建議
工業和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網安備53010202001879號 人力資源服務許可證:(云)人服證字(2023)第0102001523號
云南網警備案專用圖標
聯系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關注公眾號:hfpxwx
咨詢QQ:1093837350(9:00—18:00)版權所有:易賢網
云南網警報警專用圖標
中文字幕免费精品_亚洲视频自拍_亚洲综合国产激情另类一区_色综合咪咪久久
国产精品s色| 亚洲人成在线播放| 尤物九九久久国产精品的特点| 亚洲国产乱码最新视频| 国产精品免费小视频| 91久久久久久久久久久久久| 久久精品1区| 国产一区二区高清不卡| 毛片一区二区三区| 亚洲国产裸拍裸体视频在线观看乱了| 久久久国产视频91| 亚洲免费av网站| 欧美日本中文字幕| 亚洲欧美精品一区| 欧美黄色影院| 欧美亚洲免费在线| 精品不卡视频| 欧美国产一区二区在线观看| 亚洲精品一区久久久久久| 欧美视频中文字幕在线| 午夜欧美精品久久久久久久| 国产一区二区三区四区三区四| 久久亚洲捆绑美女| 亚洲国产色一区| 国产精品中文在线| 免费日本视频一区| 亚洲视频精选在线| 亚洲精品国产精品国自产在线 | 亚洲成人原创| 美女啪啪无遮挡免费久久网站| 亚洲狠狠婷婷| 欧美系列亚洲系列| 久久亚洲欧美| 香蕉亚洲视频| 亚洲国产一区二区三区青草影视| 欧美日本一道本| 久久这里只有| 亚洲视频第一页| 韩国女主播一区| 国产情侣久久| 欧美人成网站| 久久国产精品久久w女人spa| 黄色成人片子| 韩日精品在线| 欧美日韩中文在线观看| 亚洲一区影音先锋| 1024成人| 国产精品日韩| 欧美日本一区二区三区| 欧美一级专区| 亚洲视频中文字幕| 国产午夜精品理论片a级探花| 久久综合久色欧美综合狠狠| 久久久久一区二区三区四区| 亚洲一区亚洲| 亚洲精品国产视频| 夜夜狂射影院欧美极品| 亚洲国产精品t66y| 国产日韩欧美在线一区| 国产网站欧美日韩免费精品在线观看 | 西瓜成人精品人成网站| 亚洲国产欧美日韩另类综合| 国产精品日日做人人爱| 欧美mv日韩mv国产网站| 欧美大胆a视频| 久久综合免费视频影院| 午夜视频一区在线观看| 欧美一区二区三区四区在线观看| 亚洲午夜免费视频| 一本大道久久a久久精二百| 日韩一区二区精品| 99精品免费视频| 亚洲精品视频一区二区三区| 亚洲麻豆视频| 一本色道久久综合亚洲精品小说 | 国产偷国产偷精品高清尤物| 国产伦精品一区二区三| 国产精品美女久久久久久2018 | 在线播放亚洲一区| 国产日韩精品视频一区二区三区 | 伊人伊人伊人久久| 国产日韩欧美麻豆| 国产精品久久久久免费a∨| 狠狠色狠狠色综合日日五| 国产日韩欧美精品在线| 国产一区二区三区在线观看精品| 国产热re99久久6国产精品| 黄色成人在线网址| 在线观看日韩av先锋影音电影院| 激情综合色综合久久| 日韩视频在线观看免费| 亚洲视频免费观看| 亚洲欧美在线一区二区| 狂野欧美激情性xxxx欧美| 欧美成熟视频| 欧美精品导航| 欧美日本高清视频| 国产日韩欧美自拍| 亚洲电影网站| 亚洲人在线视频| 久久国产天堂福利天堂| 久久综合久久综合久久| 免费一级欧美片在线观看| 欧美性大战久久久久| 国产一区亚洲| 一区二区三区在线免费视频| 亚洲精品国产精品乱码不99| 亚洲欧洲午夜| 久久久久中文| 欧美另类变人与禽xxxxx| 国产精品青草久久| 欧美日韩一区二区三区视频| 国内成人自拍视频| 日韩午夜在线观看视频| 亚洲一区二区三区中文字幕| 久久久蜜桃一区二区人| 欧美激情综合五月色丁香小说| 欧美成人精品一区| 在线看国产一区| 亚洲精品看片| 久久亚洲精品一区| 麻豆国产va免费精品高清在线| 欧美精品在线免费| 在线成人亚洲| 久久久久久999| 国产日韩欧美在线播放不卡| 一区二区免费看| 欧美精品激情在线| 亚洲激情第一页| 免费影视亚洲| 亚洲国产成人av在线| 久久久久久久久久久久久久一区| 国产精品国产三级国产普通话蜜臀| 最新国产成人av网站网址麻豆| 久久久久国产精品一区二区| 久久视频一区二区| 免费日韩av| 国产精品日韩高清| 一本色道久久综合精品竹菊| 欧美 日韩 国产 一区| 黄色av一区| 久久综合激情| 亚洲国产成人porn| 欧美紧缚bdsm在线视频| 亚洲欧洲精品一区二区三区波多野1战4| 久久精品国产亚洲一区二区三区| 国产性做久久久久久| 久久精品国产清自在天天线| 国内精品久久国产| 久久天天躁狠狠躁夜夜av| 一区二区三区在线免费观看| 久久久精品视频成人| 136国产福利精品导航网址应用| 久久久久久久久蜜桃| 亚洲第一区中文99精品| 欧美激情1区| 亚洲激情在线观看| 欧美久久一级| 国产精品videosex极品| 欧美日本在线一区| 亚洲一级电影| 国产精品视频福利| 久久久精品欧美丰满| 伊人成人在线视频| 欧美精品久久久久久久久久| 99re热精品| 国产婷婷精品| 欧美华人在线视频| 亚洲欧美日韩国产成人精品影院| 国产欧美日韩视频一区二区| 久久人人九九| 一区二区三区视频在线播放| 国产视频在线观看一区二区| 免费观看国产成人| 亚洲伊人观看| 亚洲黄色在线| 国产伦精品一区二区三区免费迷 | 国产亚洲欧美一区二区| 性娇小13――14欧美| 美女精品国产| 99在线视频精品| 国内成+人亚洲| 欧美日韩亚洲一区二区三区四区| 欧美一区二区三区免费在线看| 亚洲国产高清aⅴ视频| 国产精品你懂的在线欣赏| 欧美成人一区二区| 欧美在线免费观看亚洲| 夜夜爽www精品| 亚洲高清不卡| 韩国欧美一区| 国产精品入口夜色视频大尺度| 欧美二区在线播放| 久久一区二区三区超碰国产精品| 亚洲在线一区二区| 一区二区三区四区国产| 亚洲人成网站精品片在线观看| 国内在线观看一区二区三区| 国产乱理伦片在线观看夜一区| 欧美日韩精品三区|