精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

構建你第一個JavaScript框架

開發 前端 開發工具
我們幾乎每天都在使用各種各樣的JavaScript框架。當你剛入門的時候,方便的DOM(文檔對象模型)操作讓你覺得JQuery這樣的東西非常棒。

覺得Mootools不可思議?想知道Dojo是如何實現的?對JQuery的技巧感到好奇?在這篇教程里,我們將探尋框架背后的秘密,然后試著自己動手建立一個你所喜愛的框架的簡易版本。

我們幾乎每天都在使用各種各樣的JavaScript框架。當你剛入門的時候,方便的DOM(文檔對象模型)操作讓你覺得JQuery這樣的東西非常棒。這是因為:首先,對于新手來說DOM太難理解了;當然,對于一個API來說難以理解可不是什么好事。其次,瀏覽器間的兼容性問題非常令人困擾。

我們將元素包裝成對象是因為我們想要能夠為對象添加方法。

在這個教程里,我們將試著從頭實現這些框架之一。是的,這會很有趣,不過在你太過興奮前我要澄清幾點:

這不會是一個功能很完善的框架。的確,我們要寫很多東西,但它還算不上JQuery。可是我們將要做的事情會讓你體驗到在真正編寫框架的感覺。

我們不打算保證全方位的兼容性。我們將要編寫的框架能夠在 Internet Explorer 8+、Firefox 5+、Opera 10+、Chrome和Safari上工作。

我們的框架不會覆蓋到所有可能的功能。比如說,我們的append和preappend方法只有在你傳給它一個我們框架的實例時才能工作;我們不會用原生的DOM節點和節點列表。

另外:盡管在教程中我們不會為我們的框架編寫測試用例,但是我已經在第一次開發它的時候做好了。你可以從 Github上獲取框架和測試用例的代碼。

第一步: 創建框架模板

我們將從一些包裝代碼開始,它將容納我們的整個框架。這是典型的立即函數(IIFE).

  1. window.dome = (function () {  
  2.     function Dome (els) {  
  3.     }  
  4.     var dome = {  
  5.         get: function (selector) {  
  6.         }  
  7.     };  
  8.     return dome;  
  9. }()); 

你可以看到,我們的框架叫做dome,因為它是一個基本的DOM框架。沒錯,基本(lame有“瘸子”、“不完整”的意思,dom加lame等于dome)的。

我們已經有了一些東西。 首先,我們有了一個函數;它將成為構造框架的對象實例的構造函數;那些對象將會包含我們選擇和創建的元素。

然后,我們有了一個dome對象,它就是我們的框架對象;你可以看到它最終作為函數的返回值返回給了函數調用者(譯注:賦值給了window.dome)。這里還有一個空的get函數,我們將用它從頁面里選取元素。那么,我們來填充代碼吧。

第二步: 獲取元素

dome的get函數只有一個參數,但是它可以是很多東西。如果它一個string(字符串),我們將假定它是一個CSS(層疊樣式表)選擇器;不過我們也可能得到一個DOM節點或者DOM節點列表。

  1. get: function (selector) {  
  2.     var els;  
  3.     if (typeof selector === "string") {  
  4.         els = document.querySelectorAll(selector);  
  5.     } else if (selector.length) {  
  6.         els = selector;  
  7.     } else {  
  8.         els = [selector];  
  9.     }  
  10.     return new Dome(els);  

我們用document.querySelectorAll來簡單的選擇元素:當然,這將限制我們的瀏覽器兼容性,不過對于這種情況還是可以接受的。如果 selector不是string類型,我們將檢查它的length屬性。如果存在,我們就知道我們得到的是一個節點列表;否則,就是一個單獨的元素,我們將它放到一個數組里。這是因為我們要在下面向Dome傳遞一個數組。你可以看到,我們返回了一個新的Dome對象。讓我們回到Dome函數并且為它填充代碼。

第三步: 創建Dome實例

這是Dome函數:

  1. function Dome (els) {  
  2.     for(var i = 0; i < els.length; i++ ) {  
  3.         this[i] = els[i];  
  4.     }  
  5.     this.length = els.length;  

我強烈建議你去深入研究一些你喜歡的框架

這非常簡單:我們只是遍歷了els的所有元素,并且把它們存儲在一個以數字為索引的新對象里。然后我們添加了一個length屬性。

但是這有什么意義呢?為什么不直接返回元素?因為:我們將元素包裝成對象是因為我們想要能夠為對象添加方法;這些方法能夠讓我們遍歷這些元素。實際上這正是JQuery的解決方案的濃縮版。

我們的Dome對象已經返回了,現在讓我們來為它的原型(prototype)添加一些方法。我會直接把那些方法寫在Dome函數下面。

第四步:添加幾個實用工具

要添加的第一批功能是些簡單的工具函數。由于Dome對象可能包含至少一個DOM元素,那么我們需要在幾乎每一個方法里面都遍歷所有元素;這樣,這些工具才會給力。

我們從一個map函數開始:   

  1. Dome.prototype.map = function (callback) {  
  2.     var results = [], i = 0;  
  3.     for ( ; i < this.length; i++) {  
  4.         results.push(callback.call(thisthis[i], i));  
  5.     }  
  6.     return results;  
  7. }; 

當然,這個map函數有一個入參,一個回調函數。我們遍歷Dome對象所有元素,收集回調函數的返回值到結果集中。注意我們是怎樣調用回調函數的:

  1. callback.call(thisthis[i], i)); 

通過這種方式,函數將在Dome實例的上下文中被調用,并且函數接收到兩個參數:當前元素和元素序號。

我們也想要一個foreach函數。事實上這很簡單:

  1. Dome.prototype.forEach(callback) {  
  2.     this.map(callback);  
  3.     return this;  
  4. }; 

由于map函數和foreach函數之間的不同僅僅是map需要返回些東西,我們可以僅僅將回調傳給this.map然后忽略返回的數組;代替返回的是,我們將返回this,來使我們的庫呈鏈式。foreach會被頻繁的調用,所以,注意當一個函數的回調被返回,事實上,返回的是Dome實例。例如,下面的方法事實上就返回了Dome實例:

  1. Dome.prototype.someMethod1 = function (callback) {  
  2.     this.forEach(callback);  
  3.     return this;  
  4. };  
  5. Dome.prototype.someMethod2 = function (callback) {  
  6.     return this.forEach(callback);  
  7. }; 

還有一個:mapOne。很容易就知道這個函數是做什么的,但是真正的問題是,為什么需要它?這就需要一些我們稱之為"庫哲學"的東西了。

一個簡短的"哲學"闡釋

首先,對于一個初學者來說,DOM很讓人糾結;它的API不完善。

如果構建一個庫僅僅是寫代碼,那就不是什么難事。但是當我開發這個庫時,我發現那些不完善的部分決定了一定數量的方法的實現方式。

很快,我們要去構建一個返回被選擇元素的文本的text方法。如果Dome對象包含多個DOM節點(比如dome.get("li")),返回什么?如果你就像jQuery那樣($("li").text())很簡單的編寫,你將得到一個字符串,這個字符串是所有元素的文本的直接拼接。有用嗎?我認為沒用,但是我不認為沒有更好的辦法。

對于這個項目,我將以數組方式返回多個元素的文本,除非數組里只有一個元素,那么我僅僅返回一個文本字符串,而不是一個包含了一個元素的數組。我想你會經常去獲取單個元素的文本,所以我們優化了那種情況。但是,如果你想去獲取多個元素的文本,我們的返回你也會用著很爽。

回到代碼

那么,mapOne方法僅僅是簡單的運行map函數,然后返回數組,或者一個數組里的元素。如果你仍然不確定這是如何有用,堅持一下,你就會看到!

  1. Dome.prototype.mapOne = function (callback) {  
  2.     var m = this.map(callback);  
  3.     return m.length > 1 ? m : m[0];  
  4. }; 

第5步: 處理Text和HTML

接著,讓我們來添加文本方法。就像jQuery,我們可以傳遞一個string值,設置節點元素的text值,或者通過無參方法得到返回的text值。

  1. Dome.prototype.text = function (text) {  
  2.     if (typeof text !== "undefined") {  
  3.         return this.forEach(function (el) {  
  4.             el.innerText = text;  
  5.         });  
  6.     } else {  
  7.         return this.mapOne(function (el) {  
  8.             return el.innerText;  
  9.         });  
  10.     }  
  11. }; 

如你所料,當我們設置(setting)或者得到(getting)value值時,需要檢查text的值。要注意的是如果justif(文本)方法不起作用,是因為text為空字符串是一個錯誤的值。

如果我們設置(setting)時,可是使用一個forEach 遍歷元素,設置它們的innerText屬性。如果我們得到(getting)時,返回元素的innerText屬性。在使用mapOne方法是要注意:如果我們正在處理多個元素,將返回一個數組;其他的則還是一個字符串。

如果html方法使用innerHTML屬性而不是innerText,它將會更優雅的處理涉及text文本的事情。

  1. Dome.prototype.html = function (html) {  
  2.     if (typeof html !== "undefined") {  
  3.         this.forEach(function (el) {  
  4.             el.innerHTML = html;  
  5.         });  
  6.         return this;  
  7.     } else {  
  8.         return this.mapOne(function (el) {  
  9.             return el.innerHTML;  
  10.         });  
  11.     }  
  12. }; 

就像我說過的:幾乎相同的。

第六步: 修改類

下一步,我們想對class進行操作,所以添加能addClass()和removeClass()。addClass()的參數是一個class名稱或者名稱的數組。為了實現動態參數,我們需要對參數的類型進行判斷。如果參數是一個數組,那么遍歷這個數組,將元素添加上這些class名稱,如果參數是一個字符串,則直接加上這個class名稱。函數需要確保不將原來的class名稱弄亂。

  1. Dome.prototype.addClass = function (classes) {  
  2.     var className = "";  
  3.     if (typeof classes !== "string") {  
  4.         for (var i = 0; i < classes.length; i++) {  
  5.             className += " " + classes[i];  
  6.         }  
  7.     } else {  
  8.         className = " " + classes;  
  9.     }  
  10.     return this.forEach(function (el) {  
  11.         el.className += className;  
  12.     });  
  13. }; 

很直觀吧?嘿嘿

現在,寫下removeClass(),同樣簡單。不過每次只允許刪除一個class名稱。

  1. Dome.prototype.removeClass = function (clazz) {  
  2.     return this.forEach(function (el) {  
  3.         var cs = el.className.split(" "), i;  
  4.         while ( (i = cs.indexOf(clazz)) > -1) {  
  5.             cs = cs.slice(0, i).concat(cs.slice(++i));  
  6.         }  
  7.         el.className = cs.join(" ");  
  8.     });  
  9. };  

對于每一個元素,我們都將el.className 分割成一個字符串數組。那么我們使用一個while循環連接,直到cs.indexOf(clazz)返回值大于-1。我們將得到的結果join成el.className。

第七步: 修復一個IE引起的BUG

我們處理的最糟瀏覽器是IE8.在這個小小的庫中,只有一個IE引起的BUG需要去修復; 并且謝天謝地,修復它非常簡單.IE8不支持Array的方法indexOf;我們需要在removeClass方法中使用到它, 下面讓我們來完成它:

  1. if (typeof Array.prototype.indexOf !== "function") {  
  2.     Array.prototype.indexOf = function (item) {  
  3.         for(var i = 0; i < this.length; i++) {  
  4.             if (this[i] === item) {  
  5.                 return i;  
  6.             }  
  7.         }  
  8.         return -1;  
  9.     };  

它看上去非常簡單,并且它不是完整實現(不支持使用第二個參數),但是它能實現我們的目標.

第8步: 調整屬性

現在,我們想要一個attr函數。這將很容易,因為它幾乎和text方法或者html方法是一樣的。像這些方法,我們都能夠設置和得到屬性:我們將設置一個屬性的名稱和值,同時只通過參數名來得到值。

  1. Dome.prototype.attr = function (attr, val) {  
  2.     if (typeof val !== "undefined") {  
  3.         return this.forEach(function(el) {  
  4.             el.setAttribute(attr, val);  
  5.         });  
  6.     } else {  
  7.         return this.mapOne(function (el) {  
  8.             return el.getAttribute(attr);  
  9.         });  
  10.     }  
  11. }; 

如果形參有一個值,我們將遍歷元素并通過元素的setAttribute方法設置屬性值。另外,我們將使用mapOne返回通過getAttribute方法得到參數。

第9步: 創建元素

像任何一個優秀的框架一樣,我們也應該能夠創建元素。當然,在Demo實例中沒有一個好的方法,所以讓我們來把方法加入到demo工程中。

  1. var dome = {  
  2.     // get method here  
  3.     create: function (tagName, attrs) {  
  4.     }  
  5. }; 

正如你所看到的:我們需要兩個形參:元素名,和一個參數對象。大多數的屬性通過我們的arrt方法被使用,但是tagName和attrs卻有特殊待遇。我們為className屬性使用addClass方法,為text屬性使用text方法。當然,我們首先要創建元素,和Demo對象。下面就是所有的作用:

  1. create: function (tagName, attrs) {  
  2.     var el = new Dome([document.createElement(tagName)]);  
  3.         if (attrs) {  
  4.             if (attrs.className) {  
  5.                 el.addClass(attrs.className);  
  6.                 delete attrs.className;  
  7.             }  
  8.         if (attrs.text) {  
  9.             el.text(attrs.text);  
  10.             delete attrs.text;  
  11.         }  
  12.         for (var key in attrs) {  
  13.             if (attrs.hasOwnProperty(key)) {  
  14.                 el.attr(key, attrs[key]);  
  15.             }  
  16.         }  
  17.     }  
  18.     return el;  

如上,我們創建了元素,將他發送到新的Dmoe對象中。接著,我們處理所有屬性。注意:當使用完className和text屬性后,我們不得不刪除他們。這將保證當我們遍歷其他的鍵時,它們還能被使用。當然,我們最終通過返回這個新的Demo對象。

我們創建了新的元素,我們想要將這些元素插入到DOM,對吧?

第10步:尾部添加(Appending)與頭部添加(Prepending)元素

下一步,我們來實現尾部添加與頭部添加方法??紤]到多種場景,實現這些方法可能有些棘手。下面是我們的想要達到的效果:

  1. dome1.append(dome2);  
  2. dome1.prepend(dome2); 

IE8對我們來說就是一奇葩。

尾部添加或頭部添加,包括以下幾種場景:

單個新元素添加至單個或多個已存在元素中

多個新元素添加至單個或多個已存在元素中

單個已存在元素添加至單個或多個已存在元素中

多個已存在元素添加至單個或多個已存在元素中

注意:這里的”新元素“表示還未加入DOM中節點元素,”已存在元素“指已存在于DOM中的節點元素。
現在讓我們一步步來實現之:

  1. Dome.prototype.append = function (els) {  
  2.     this.forEach(function (parEl, i) {  
  3.         els.forEach(function (childEl) {  
  4.         });  
  5.     });  
  6. }; 

假設參數els是一個DOM對象。一個功能完備的DOM庫應該能處理節點(node)或節點序列(nodelist),但現在我們不作要求。首先遍歷需要被添加進的元素 (父元素),再在這個循環中遍歷將被添加的元素 (子元素)。 

如果將一個子元素添加至多個父元素,需要克隆子元素(避免最后一次操作會移除上一次添加操作)??墒?,沒必要在初次添加的時候就克隆,只需要在其它循環中克隆就可以了。因此處理如下:

  1. if (i > 0) {  
  2.     childEl = childEl.cloneNode(true);  

變量i來自外層forEach循環:它表示父級元素的序列號。第一個父元素添加的是子元素本身,而其他父元素添加的都是目標子元素的克隆。因為作為參數傳入的子元素是未被克隆的,所以,當將單個子元素添加至單個父元素時,所有的節點都是可響應的。
最后,真正的添加元素操作:

  1. parEl.appendChild(childEl); 

因此,組合起來,我們得到以下實現:

  1. Dome.prototype.append = function (els) {  
  2.     return this.forEach(function (parEl, i) {  
  3.         els.forEach(function (childEl) {  
  4.             if (i > 0) {  
  5.                 childEl = childEl.cloneNode(true);  
  6.             }  
  7.             parEl.appendChild(childEl);  
  8.         });  
  9.     });  
  10. }; 

prepend方法

我們按照相同的邏輯實現prepend方法,其實也相當簡單。

  1. Dome.prototype.prepend = function (els) {  
  2.     return this.forEach(function (parEl, i) {  
  3.         for (var j = els.length -1; j > -1; j--) {  
  4.             childEl = (i > 0) ? els[j].cloneNode(true) : els[j];  
  5.             parEl.insertBefore(childEl, parEl.firstChild);  
  6.         }  
  7.     });  
  8. }; 

不同點在于添加多個元素時,添加后的順序會被反轉。所以不能采用forEach循環,而是用倒序的for循環代替。同樣的,在添加至非第一個父元素時需克隆目標子元素。

第十一步: 刪除節點

對于我們最后一個節點的操作方法,從dom中刪除這些節點,很簡單,只需要:

  1. Dome.prototype.remove = function () {  
  2.     return this.forEach(function (el) {  
  3.         return el.parentNode.removeChild(el);  
  4.     });  
  5. }; 

只需要通過節點的迭代和在他們的父節點調用刪除子節點方法。比較好的是這個dom對象依然正常工作(感謝文檔對象模型吧)。我們可以在它上面使用我們想使用的方法,包括插入,預插回DOM,很漂亮,不是嗎?

第12步:事件處理

最后,卻是最重要的一環,我們要寫幾個事件處理函數。

如你所知,IE8依然使用舊的IE事件,因此我們需要為此作檢測。同時,我們也要做好使用DOM 0 級事件的準備。

查看下面的方法,我們稍后會討論:

  1. Dome.prototype.on = (function () {  
  2.     if (document.addEventListener) {  
  3.         return function (evt, fn) {  
  4.             return this.forEach(function (el) {  
  5.                 el.addEventListener(evt, fn, false);  
  6.             });  
  7.         };  
  8.     } else if (document.attachEvent)  {  
  9.         return function (evt, fn) {  
  10.             return this.forEach(function (el) {  
  11.                 el.attachEvent("on" + evt, fn);  
  12.             });  
  13.         };  
  14.     } else {  
  15.         return function (evt, fn) {  
  16.             return this.forEach(function (el) {  
  17.                 el["on" + evt] = fn;  
  18.             });  
  19.         };  
  20.     }  
  21. }()); 

在這里,我們用到了立即執行函數(IIFE),在函數內我們做了特性檢測。如果document.addEventListener方法存在,我們就使用它;另外我們也檢測 document.attachEvent,如果沒有就使用DOM 0級方法。請注意我們如何從立即執行函數中返回最終函數:其最后會被分配到Dome.prototype.on。在做特性檢測時,與每次運行函數時檢測相比,這樣的方式分配適合的方法更加方便。

事件解綁方法off與on方法類似:.

  1. Dome.prototype.off = (function () {  
  2.     if (document.removeEventListener) {  
  3.         return function (evt, fn) {  
  4.             return this.forEach(function (el) {  
  5.                 el.removeEventListener(evt, fn, false);  
  6.             });  
  7.         };  
  8.     } else if (document.detachEvent)  {  
  9.         return function (evt, fn) {  
  10.             return this.forEach(function (el) {  
  11.                 el.detachEvent("on" + evt, fn);  
  12.             });  
  13.         };  
  14.     } else {  
  15.         return function (evt, fn) {  
  16.             return this.forEach(function (el) {  
  17.                 el["on" + evt] = null;  
  18.             });  
  19.         };  
  20.     }  
  21. }()); 

就這樣!

我真心的希望你能夠試驗一下我們的小框架,或者僅僅是繼承一點點,就想前面我提到的,我已經把這個框架放到github,帶著著我們已經寫的Jasmine 測試用例。可以自用的來fork代碼,發送pull請求。

我要重申:本文的觀點并是不推薦你一定要寫你自己的框架

這里有樂于奉獻的人一起工作來使這個框架變大,盡可能的完善。這里只是簡單講了一下框架的原理,我非常高興你能從中得到一些提示。

我真心的建議你能夠自己的研究你喜歡的框架,你會發現它們并沒有你想象的那么難懂,而且你很可能會從中學到很多東西,這里是一些很好的開始文章,

10 Things I Learned from the jQuery Source (我從jquery源碼學到的10件事)( 作者 Paul Irish )

11 More Things I Learned from the jQuery Source  (我從jquery源碼學到的11件事)(作者 Paul Irish)

Under jQuery’s Bonnet (作者 James Padolsey)

Backbone.js: Hacker’s Guide, part 1, part 2, part 3, part 4

了解其他的更好的框架? 請留言?

原文鏈接:http://www.oschina.net/translate/build-your-first-javascript-library

責任編輯:張偉 來源: oschina
相關推薦

2018-01-31 15:45:07

前端Vue.js組件

2018-08-22 17:32:45

2022-10-17 10:28:05

Web 組件代碼

2014-12-24 11:34:23

CoreOSWordPress集群部署

2025-04-18 08:01:21

AIAgent驅動力

2017-11-21 09:20:06

深度學習TensorFlow游戲AI

2018-10-15 10:10:41

Linux內核補丁

2013-12-19 09:46:04

垃圾收集器

2010-12-07 16:53:43

商業智能

2014-07-24 14:35:26

Linux內核模塊

2016-08-05 12:58:44

GitLinux開源

2016-08-24 15:12:41

LXDLinux容器

2019-12-31 08:00:00

DebianLinuxApple Swift

2023-10-09 14:32:48

2015-04-01 14:40:26

Java構建工具build.xml

2018-11-08 13:53:15

Flink程序環境

2021-04-07 13:38:27

Django項目視圖

2023-09-21 22:43:17

Django框架

2011-03-21 14:24:13

Debian 6

2010-07-30 14:58:06

Flex應用
點贊
收藏

51CTO技術棧公眾號

欧美另类交人妖| 欧美伊人久久久久久久久影院 | 久久久国产成人精品| 欧美一区二区三区影院| 丁香花在线影院| 91丝袜呻吟高潮美腿白嫩在线观看| 2019中文字幕在线观看| 日韩毛片无码永久免费看| 国产情侣一区在线| 欧美日韩一区二区精品| 一区二区在线中文字幕电影视频| 亚洲精品字幕在线| 日欧美一区二区| 欧美国产极速在线| 国产黄片一区二区三区| 国产精品美女久久久久| 色婷婷久久久久swag精品| 一本色道久久88亚洲精品综合| 天堂在线视频观看| 国精产品一区一区三区mba视频| 欧美精品18videos性欧| 四季av中文字幕| 欧美美女黄色| 日韩精品一区二区三区三区免费| 美女福利视频在线| av日韩国产| 亚洲国产精品成人久久综合一区| 俄罗斯精品一区二区三区| 国产专区第一页| 99久久www免费| 亚洲性av网站| 特级西西人体wwwww| 国产精品日本一区二区不卡视频| 日本久久一区二区三区| 成人黄色av片| 成人影音在线| 夜色激情一区二区| 在线观看18视频网站| 91女主播在线观看| 久久久美女艺术照精彩视频福利播放| 国产富婆一区二区三区 | 亚洲激情自拍图| 久久久久无码国产精品一区李宗瑞| 色综合久久久| 欧美理论电影在线| 国产精品自拍视频在线| av成人在线播放| 欧美综合一区二区| 成人性做爰aaa片免费看不忠| 老司机深夜福利在线观看| 亚洲在线观看免费视频| 久久亚洲国产成人精品无码区| 免费在线观看黄色| 国产精品久线在线观看| 亚洲va久久久噜噜噜久久狠狠 | 成人免费毛片播放| 欧美男体视频| 欧美三级日韩在线| 欧美美女一级片| 日韩综合久久| 日韩免费一区二区三区在线播放| 日韩精品在线播放视频| 亚洲**毛片| 亚洲护士老师的毛茸茸最新章节 | 国产精品欧美亚洲| 国产精品一区三区| 国产伦精品一区二区| 人妻无码中文字幕| xnxx国产精品| 亚洲欧美日韩精品在线| 国产激情小视频在线| 亚洲精品国产精华液| 国产91沈先生在线播放| 密臀av在线播放| 色94色欧美sute亚洲线路一ni| 久久黄色免费看| 欧美视频精品| 日韩亚洲欧美在线| 亚洲av无码一区二区三区网址| 日韩a级大片| 在线看片第一页欧美| 手机av在线看| 一本久道久久综合婷婷鲸鱼| 欧美一级免费视频| 6—12呦国产精品| 成人国产精品免费观看动漫| 免费看污久久久| 成人免费在线视频网| 亚洲色图.com| 国产a级一级片| 日韩三级一区| 精品视频偷偷看在线观看| 五月婷婷六月香| 影音先锋一区| 国产精品私拍pans大尺度在线| 中文字幕 国产| 丁香激情综合国产| 色播五月综合| xxx.xxx欧美| 欧美性色黄大片| 婷婷五月精品中文字幕| 欧美日韩在线播放视频| 久久久久久有精品国产| 一区二区小视频| hitomi一区二区三区精品| 亚洲日本欧美在线| 免费毛片b在线观看| 欧美日韩电影在线播放| 亚洲第一黄色网址| 欧美99在线视频观看| 国产精品都在这里| 蜜臀av午夜精品| 日韩毛片精品高清免费| 国产在线观看福利| 成人动态视频| 日韩在线视频一区| 老司机激情视频| 午夜激情成人网| 精品国产凹凸成av人导航| 精品无码在线观看| 亚洲视频大全| 成人动漫视频在线观看完整版| 成年人视频在线观看免费| 亚洲成人综合在线| 四川一级毛毛片| 欧美电影免费| 国产精品久久久一区| 手机看片1024国产| 亚洲网友自拍偷拍| 日韩高清一二三区| 一本一本久久a久久综合精品| 国产精品久久久久久超碰| 日韩成人黄色| 欧美日韩国产综合新一区| 性一交一黄一片| 欧美激情综合色综合啪啪| 国产在线久久久| 99青草视频在线播放视| 在线观看日产精品| 这里只有久久精品| 日韩精彩视频在线观看| 欧美日韩精品不卡| 在线视频超级| 亚洲男人天堂2023| 九九精品免费视频| 久久久高清一区二区三区| 免费高清一区二区三区| 亚洲超碰在线观看| 欧美精品videos另类日本| www.四虎在线观看| 亚洲一区在线视频| 人妻av一区二区| 一本色道久久综合一区| 九九九久久久| 日韩网站中文字幕| 色婷婷av一区二区三区在线观看| 日批视频免费观看| 国产精品灌醉下药二区| 日韩成人av免费| 欧美大片专区| 国产欧美日韩伦理| 亚洲精品**中文毛片| 国产小视频91| 国产又粗又猛又爽又黄视频| 亚洲欧美日韩国产一区二区三区| 日批视频在线看| 亚洲精品韩国| 欧美一区二区福利| 亚洲成a人片777777久久| 久久这里有精品| 五月婷婷丁香网| 色老汉av一区二区三区| 大吊一区二区三区| 国产乱码字幕精品高清av | 久久激情综合| 亚洲视频在线二区| 亚洲超碰在线观看| 日韩美女主播视频| 国产美女av在线| 亚洲精品久久久久久久久久久久| 无码人妻一区二区三区线| 中文字幕一区二区三区在线观看| 伊人av在线播放| 久久这里只有| 成人国产一区二区三区| 欧美午夜18电影| 成人精品久久久| 免费看男女www网站入口在线| 国产一区二区三区欧美| 国产成人久久精品77777综合| 五月开心婷婷久久| 91禁男男在线观看| heyzo一本久久综合| 日韩一级免费片| 一区二区91| 超碰免费在线公开| 亚瑟一区二区三区四区| 亚洲最大福利视频网| 美女100%一区| 欧美激情18p| av成人手机在线| 亚洲第一福利在线观看| 中文字字幕在线中文乱码| 偷窥少妇高潮呻吟av久久免费| www.涩涩爱| 国产亚洲欧洲一区高清在线观看| 午夜天堂在线视频| 石原莉奈一区二区三区在线观看| 久久久久福利视频| 日本电影一区二区| 久久偷窥视频| 国产精品巨作av| 亚洲最大av网| 日本免费在线一区| 国产精品成人国产乱一区| 爱情岛亚洲播放路线| 久热在线中文字幕色999舞| 黄色在线视频观看网站| 亚洲国产日韩欧美在线图片| av在线免费在线观看| 欧美三级电影网| 在线免费观看av网址| 香蕉加勒比综合久久| 日本青青草视频| 国产精品国产a| 国产无遮挡在线观看| 久久人人爽人人爽| 久久偷拍免费视频| 99精品国产热久久91蜜凸| 天堂va欧美va亚洲va老司机| 极品少妇一区二区三区精品视频| 亚洲性生活网站| 老司机午夜免费精品视频 | 麻豆精品在线看| 已婚少妇美妙人妻系列| 国产一区二区三区的电影| 久久亚洲精品无码va白人极品| 亚洲天堂免费| 佐佐木明希av| 欧美日韩91| av在线免费观看国产| 欧美福利电影在线观看| 路边理发店露脸熟妇泻火| 亚洲精品国产首次亮相| 自拍偷拍视频在线| 亚洲免费二区| 国产激情片在线观看| 欧美激情成人在线| 日本香蕉视频在线观看| 亚洲大片在线| 浮妇高潮喷白浆视频| 性欧美暴力猛交另类hd| 超碰网在线观看| 欧美a一区二区| 成人性生交免费看| 国产麻豆视频精品| 又色又爽又黄18网站| 成人教育av在线| 狠狠人妻久久久久久综合蜜桃| www国产成人| 亚洲黄色小说视频| 国产精品美女一区二区| 翔田千里88av中文字幕| 亚洲精品国产视频| 国产成人自拍视频在线| 欧美性极品xxxx做受| 亚洲中文一区二区| 91精品国产日韩91久久久久久| www视频在线| 亚洲精品电影网在线观看| 可以直接在线观看的av| 日韩亚洲综合在线| 欧洲黄色一区| 欧美中文字幕在线| 黄页免费欧美| 国产日本一区二区三区| 国产日产精品_国产精品毛片| 亚洲图色在线| 亚洲黄色av| 免费一级特黄录像| 国产成人精品一区二区三区四区 | 一级毛片视频在线观看| 欧美成人国产va精品日本一级| 波多野结依一区| 国产精品一区二区三区免费视频 | 亚洲精品乱码久久久久久蜜桃91 | 亚洲区小说区图片区qvod| 天天久久人人| 伊人久久大香线蕉综合热线| 日批视频在线免费看| 国内精品伊人久久久久影院对白| 国产高潮失禁喷水爽到抽搐| 久久久国际精品| 91视频免费在线看| 日本精品视频一区二区| www.五月婷婷| 中文字幕日韩av电影| 波多野结衣在线播放| 成人在线激情视频| 亚洲老女人视频免费| 特大黑人娇小亚洲女mp4| 久久精品盗摄| 69亚洲乱人伦| 亚洲欧美国产高清| 男人的天堂av网站| 亚洲成人精品久久久| 麻豆电影在线播放| 日韩av免费看网站| 国产亚洲精品美女久久| 中文字幕免费在线不卡| 水野朝阳av一区二区三区| 无码人妻丰满熟妇啪啪网站| 国产精品美日韩| 91porny九色| 亚洲精品v欧美精品v日韩精品| 超碰免费公开在线| 国产精品一香蕉国产线看观看| 色综合久久中文| 和岳每晚弄的高潮嗷嗷叫视频| 久久精品72免费观看| xxxx日本黄色| 日韩欧美在线免费| 天天干天天色天天| 色综合天天综合网国产成人网| 亚洲二区av| 亚洲成人一区二区三区| 日韩高清电影一区| 99re久久精品国产| 亚洲福利电影网| 亚洲精选一区二区三区| 欧美精品亚州精品| 精品一区二区三区中文字幕视频| 亚洲色图自拍| 美女视频黄久久| 国产3级在线观看| 欧美色图一区二区三区| 成人一区二区不卡免费| 国产成人精彩在线视频九色| 日韩aaa久久蜜桃av| 国产a级一级片| 国产午夜精品一区二区三区嫩草 | 欧美一区二区三区免费| 快射视频在线观看| 成人中文字幕+乱码+中文字幕| 欧美电影免费播放| www激情五月| 亚洲在线一区二区三区| 国产 日韩 欧美 综合| 久久久久久亚洲精品| 日韩精品免费一区二区三区竹菊| 激情五月宗合网| 91在线观看高清| 天天干,天天干| 中文字幕最新精品| 国产精品成人**免费视频| 久久福利一区二区| 成人毛片在线观看| 你懂的国产在线| 尤物tv国产一区| 国产亚洲观看| 91成人综合网| 91小视频免费看| 在线观看亚洲黄色| 久久精品国产一区二区电影| 国产一区二区三区免费观看在线| 一二三四中文字幕| av中文字幕不卡| 波多野结衣视频在线观看| 综合激情国产一区| 日本在线视频一区二区三区| 国产一区二区三区小说| 2019国产精品| 一区二区国产欧美| 久久久噜噜噜久噜久久| 亚欧洲精品视频在线观看| www.久久91| 亚洲国产日韩一级| 国产三级视频在线看| 91精品国产高清久久久久久91裸体 | 成人99免费视频| 亚洲天堂视频在线播放| 欧美成人免费一级人片100| 免费福利视频一区| 欧美成人黄色网址| 亚洲最新视频在线观看| 久蕉在线视频| 成人永久免费| 日韩国产高清在线| 久久免费公开视频| 在线看欧美日韩| 麻豆一区二区| www.五月天色| 日韩欧美成人精品| h片在线免费| 色就是色欧美| av在线不卡免费看| 国产精品一级二级| 日本成人精品在线| 一区久久精品| www.av免费|