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

首頁 > 語言 > JavaScript > 正文

淺談jQuery事件綁定原理

2024-05-06 16:13:30
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了淺談jQuery事件綁定原理,并做了簡單分析,然后用實例來展示,需要的朋友可以參考下
 
 

jq里面有一個data的方法,給dom元素綁定相關的數據的。當給dom用jq的方法綁定了事件,會生成對應的時間列表
可以看下面的例子(請在firefox中查看 因為firefox中對象支持toSource())

 

復制代碼代碼如下:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title></title>
</head>
<body>
<div id="test"></div>
<script type="text/javascript" src="http://common.cnblogs.com/script/jquery.js"></script>
<script type="text/javascript">
    window.onload = function(){
        alert($.data($('#test')[0],'events'));//null
        alert($.data($('#test')[0],'handle'));//null
        $('#test')
        .bind('click',function(){
            alert(1)
        })
        .bind('mouseover',function(){
            alert(2)
        })
        .bind('click',function(){
            alert(3)
        })
        .bind('click',function(){
            alert(4)
        })
        alert($.data($('#test')[0],'events').toSource());//時間列表
        alert($.data($('#test')[0],'handle').toSource());//執行的函數
    }
</script>
</body>
</html>

 
data是給元素綁定數據的
數據源是 cache對象
當元素綁定數據的時候 會給元素添加一個屬性   jQueryxxx      xxx為執行jq的時間戳
這里要說明一下,有一個uuid 他是累加的
jQueryxxx的值就是這個uuid
cache 的 key就是這個 uuid
value就是要存的數據
data對于事件的綁定是很重要的................................

 

 

復制代碼代碼如下:

function now(){  
    return +new Date;  
}; 
var win     = this,
    expando = "jQuery" + now(),  
       uuid    = 0,   
      cache   = {};
win.data = function(elem, name, data){  
    var id = elem[expando];  
    if(!id)  
        id = elem[expando] = ++uuid;  
    if(name&&!cache[id])  
        cache[id] = {};  
    if(data !== undefined)  
        cache[id][name] = data;  
    return name  
        ? cache[id][name]  
        : id;  
}
win.removeData = function(elem, name){  
    var id = elem[expando];  
    if (name){  
        if (cache[id]) {  
            delete cache[id][name];  
            name = "";  
            for ( name in cache[ id ] )  
                break;  
            if ( !name )  
                removeData(elem);  
        }   
    }else{    
            try {  
                delete elem[expando];  
            } catch(e){  
                if ( elem.removeAttribute )  
                    elem.removeAttribute( expando );  
            }  
            delete cache[id];  
    }  
}

 

win.each = function( object, callback, args ) {  
    var name, i = 0, length = object.length;  
    if ( args ) {  
        if ( length === undefined ) {  
            for ( name in object )  
                if ( callback.apply( object[ name ], args ) === false )  
                    break;  
        } else  
            for ( ; i < length; )  
                if ( callback.apply( object[ i++ ], args ) === false )  
                    break;  
    } else {  
        if ( length === undefined ) {  
            for ( name in object )  
                if ( callback.call( object[ name ], name, object[ name ] ) === false )  
                    break;  
        } else  
            for ( var value = object[0];  
                i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}  
    }  
    return object;  
}


 
接著實現添加事件

 

jq里面是在 jQuery.event里面的add方法
在add方法里面實現了一下一些功能
取元素的events,handle這2個data綁定的數據
events存放的是事件列表
格式如下
{
click: [{handler:function(){},type:"click",guid:'xx'}.......],
mouse:[......]
}
handle是執行的函數
(所有的執行函數都是一樣的 他們遍歷事件列表    執行對應的事件) 
然后遍歷types   因為可以綁定多個事件
回調函數也會給幾個屬性
假設回調函數是handler
handler.guid = gevent.guid++
handler.type =  name
name應該算一個特殊的命名  方便刪除用的
比如
$('#xx')
.bind('click',function(){})
.bind('click.d',handler)
name就是d了
刪除的時候可以只刪除d那個事件  不刪除上面的那個 click事件
 
最后是給元素綁定事件 但是執行的函數都是
function(){
 gevent.handle.apply(arguments.callee.elem, arguments);
});

 

復制代碼代碼如下:

win.gevent = {
    guid : 1,
    add  : function (elem, types, handler){
        if ( elem.nodeType == 3 || elem.nodeType == 8 )
            return;
        if ( elem.setInterval && elem != window )
            elem = window;
        //給函數一個唯一標識的索引  方便后面刪除該事件    
        if ( !handler.guid )
            handler.guid = this.guid++;
        //獲得該元素的events handle 下的數據    
        var events = data(elem, "events") || data(elem, "events", {}),
            handle =data(elem, "handle") || data(elem, "handle", function(){
                //gevent.handle才是各種行為觸發后會執行的函數
                gevent.handle.apply(arguments.callee.elem, arguments);
            });
        handle.elem = elem;
        //遍歷事件名 因為可以是 click mouseover 
        each(types.split(//s+/), function(index, type) {
            var namespaces = type.split(".");
            //獲得事件名
            type = namespaces.shift();
            //去掉點后面的東西 是個特殊的命名  在刪除的時候可以指定刪除他  如 click.d
            //用事件的type 記錄住這個特殊的命名
            handler.type = namespaces.slice().sort().join(".");
            //獲得該事件是否已經存在events 這個對象里面了
            var handlers = events[type];
            //如果不存在該事件 給元素綁定該事件                
            if (!handlers) {
                handlers = events[type] = {};
                if (elem.addEventListener)
                    elem.addEventListener(type, handle, false);
                else if (elem.attachEvent)
                    elem.attachEvent("on" + type, handle);                                        
            }
            //吧函數放到元素的該事件的列表里面
            handlers[handler.guid] = handler;                                        
        });
        elem = null;                                                    
    }
}

 
gevent.hander是綁定事件真正執行的函數
在gevent.hander里面也有取.特殊命名的地方  但是不知道做什么用的
hander里面先對event進行包裝
包裝見gevent. fix 和 setEvent
主要是對做一個原生event的一個copy  然后把不兼容的方法  都合成兼容的寫法
然后取元素的events (事件列表)
然后遍歷這個事件列表  判斷type是不是事件列表的key 是的話就執行事件
在執行列表函數的時候會判斷返回值
如果返回false  還可以組織事件冒泡 和 默認行為

 

 

復制代碼代碼如下:

win.gevent = {
    handle : function(event){
        var all, handlers;
        //包裝event
        event = arguments[0] = gevent.fix( event || window.event );
        event.currentTarget = this;
        //這里的........
        var namespaces = event.type.split(".");
        event.type = namespaces.shift();
        all = !namespaces.length;
        var namespace = RegExp("(^|//.)" + namespaces.slice().sort().join(".*//.") + "(//.|$)");
        //取這個元素的該行為 的 事件列表
        handlers = (data(this, "events") || {} )[event.type];            
        //遍歷這個事件列表 執行該執行的東西
        for ( var j in handlers ) {
            var handler = handlers[j];
            if ( all || namespace.test(handler.type) ) {
                // Pass in a reference to the handler function itself
                // So that we can later remove it
                // jq上的注釋是是這么寫的 把event的handler 引用這個事件 方便之后移除
                // 但是在remove里面 并沒有用到event的handler  不知道這里到底有什么用  且有多個事件的時候這個事件被取代
                event.handler = handler;
                //執行事件 并且是用元素調用的事件 可以吧事件里面的this執行元素 ret為函數的返回值
                var ret = handler.apply(this, arguments);
                //如果有返回值  且返回值是false 執行阻止事件冒泡 阻止執行事件默認行為                        
                if( ret !== undefined ){
                    event.result = ret;
                    if ( ret === false ) {
                        event.preventDefault();
                        event.stopPropagation();
                    }
                }    
            }                
        }
    },
    props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),        
    fix : function(event){
        //new setEvent會給event給以個expando屬性 如果有中個屬性 說明已經生成了event了 不需要在次對event進行包裝
        if ( event[expando] )
            return event;
        //保留一個原始的event
        // new一個新的event 這個與原始的event是不同的
        var originalEvent = event;
        event = new setEvent( originalEvent );
        //獲得原始event的屬性值  有哪些屬性值 見 this.props
        for ( var i = this.props.length, prop; i; ){
            prop = this.props[ --i ];
            event[ prop ] = originalEvent[ prop ];
        }
        //將目標元素同一成event.target
        if ( !event.target )
            event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
        //如果發現是文本節點 取他的父節點
        if ( event.target.nodeType == 3 )
            event.target = event.target.parentNode;
        
        if ( !event.relatedTarget && event.fromElement )
            event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;                            
        return event;
    }        
}
win.setEvent = function(src){
    // Allow instantiation without the 'new' keyword
    // Event object
    if( src && src.type ){
        this.originalEvent = src;
        this.type = src.type;
    // Event type
    }else
        this.type = src;
    // timeStamp is buggy for some events on Firefox(#3843)
    // So we won't rely on the native value
    this.timeStamp = now();
    // Mark it as fixed
    this[expando] = true;
}
function returnFalse(){
    return false;
}
function returnTrue(){
 return true;
}
setEvent.prototype = {
 preventDefault: function() {    
     var e = this.originalEvent;
     if( !e )
         return;
     // if preventDefault exists run it on the original event
     if (e.preventDefault)
         e.preventDefault();
     // otherwise set the returnValue property of the original event to false (IE)
     e.returnValue = false;
 },
 stopPropagation: function() {    
     var e = this.originalEvent;
     if( !e )
         return;
     // if stopPropagation exists run it on the original event
     if (e.stopPropagation)
         e.stopPropagation();
     // otherwise set the cancelBubble property of the original event to true (IE)
     e.cancelBubble = true;
 },
 stopImmediatePropagation:function(){
     this.isImmediatePropagationStopped = returnTrue;
     this.stopPropagation();
 },
 isImmediatePropagationStopped: returnFalse
};    

 

一個完整的例子

 

復制代碼代碼如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title></title>
</head>
<body>
<div id="vv" style="height:200px;width:200px; background-color:#f00; padding:20px;">
<div id="xx" style="height:200px;width:200px; background-color:#000000;"></div>
</div>
<script type="text/javascript">
(function(doc,undefined){
function now(){
return +new Date;
};
var win     = this,
expando = "jQuery" + now(),
uuid    = 0,
cache   = {};
win.data = function(elem, name, data){
var id = elem[expando];
if(!id)
id = elem[expando] = ++uuid;
if(name&&!cache[id])
cache[id] = {};
if(data !== undefined)
cache[id][name] = data;
return name
? cache[id][name]
: id;
}
win.removeData = function(elem, name){
var id = elem[expando];
if (name){
if (cache[id]) {
delete cache[id][name];
name = "";
for ( name in cache[ id ] )
break;
if ( !name )
removeData(elem);
}
}else{
try {
delete elem[expando];
} catch(e){
if ( elem.removeAttribute )
elem.removeAttribute( expando );
}
delete cache[id];
}
}
win.each = function( object, callback, args ) {
var name, i = 0, length = object.length;
if ( args ) {
if ( length === undefined ) {
for ( name in object )
if ( callback.apply( object[ name ], args ) === false )
break;
} else
for ( ; i < length; )
if ( callback.apply( object[ i++ ], args ) === false )
break;
} else {
if ( length === undefined ) {
for ( name in object )
if ( callback.call( object[ name ], name, object[ name ] ) === false )
break;
} else
for ( var value = object[0];
i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
}
return object;
}
win.gevent = {
guid : 1,
add  : function (elem, types, handler){
if ( elem.nodeType == 3 || elem.nodeType == 8 )
return;
if ( elem.setInterval && elem != window )
elem = window;
//給函數一個唯一標識的索引  方便后面刪除該事件
if ( !handler.guid )
handler.guid = this.guid++;
//獲得該元素的events handle 下的數據
var events = data(elem, "events") || data(elem, "events", {}),
handle =data(elem, "handle") || data(elem, "handle", function(){
//gevent.handle才是各種行為觸發后會執行的函數
gevent.handle.apply(arguments.callee.elem, arguments);
});
handle.elem = elem;
//遍歷事件名 因為可以是 click mouseover
each(types.split(//s+/), function(index, type) {
var namespaces = type.split(".");
//獲得事件名
type = namespaces.shift();
//去掉點后面的東西 是個特殊的命名  在刪除的時候可以指定刪除他  如 click.d
//用事件的type 記錄住這個特殊的命名
handler.type = namespaces.slice().sort().join(".");
//獲得該事件是否已經存在events 這個對象里面了
var handlers = events[type];
//如果不存在該事件 給元素綁定該事件
if (!handlers) {
handlers = events[type] = {};
if (elem.addEventListener)
elem.addEventListener(type, handle, false);
else if (elem.attachEvent)
elem.attachEvent("on" + type, handle);
}
//吧函數放到元素的該事件的列表里面
handlers[handler.guid] = handler;
});
elem = null;
},
remove: function(elem, types, handler) {
if ( elem.nodeType == 3 || elem.nodeType == 8 )
return;
//獲取這個元素的所有行為列表  如 {click:{},mouseocer:{}}
var events = data(elem, "events"), ret, index;
if(events){
//如果沒出入行為類型 則刪除這個元素的所有事件
//如果傳入的是.xx這種形式的 把所有行為的包含.xx命名的全部干掉
if ( types === undefined || (typeof types === "string" && types.charAt(0) == ".") ){
for ( var type in events )
this.remove( elem, type + (types || "") );
}else{
//不知道干嘛的
if ( types.type ) {
handler = types.handler;
types = types.type;
}
//因為刪除事件可以一次支持刪除多個 如click mouseover  所有要遍歷刪除
each(types.split(//s+/),function(index, type){
var namespaces = type.split(".");
type = namespaces.shift();
var namespace = RegExp("(^|//.)" + namespaces.slice().sort().join(".*//.") + "(//.|$)");
if ( events[type] ) {
//如果傳了第3個參數 函數  則刪除這個事件
if ( handler )
delete events[type][handler.guid];
else{
//遍歷中個這個的所有行為
for ( var handle in events[type] ){
// Handle the removal of namespaced events
//刪除有特殊命名的函數
//如果沒有特殊命名 正則 則是/^|..|$/ 可以匹配空 所以也能刪除掉沒有特殊命名的函數
if ( namespace.test(events[type][handle].type) )
delete events[type][handle];
}
}
}
for ( ret in events[type] ) break;
//如果events[type]變成空的了 也就是{} 刪除這個元素的的綁定事件
if ( !ret ) {
if (elem.removeEventListener)
elem.removeEventListener(type, data(elem, "handle"), false);
else if (elem.detachEvent)
elem.detachEvent("on" + type, data(elem, "handle"));
ret = null;
delete events[type];
}
});
}
for ( ret in events ) break;
//如果發現元素的整個events都是空的了
//清空掉handle 并且清空掉他所有的引用
if ( !ret ) {
var handle = data( elem, "handle" );
if ( handle ) handle.elem = null;
removeData( elem, "events" );
removeData( elem, "handle" );
}
}
},
handle : function(event){
var all, handlers;
//包裝event
event = arguments[0] = gevent.fix( event || window.event );
event.currentTarget = this;
//這里的........
var namespaces = event.type.split(".");
event.type = namespaces.shift();
all = !namespaces.length;
var namespace = RegExp("(^|//.)" + namespaces.slice().sort().join(".*//.") + "(//.|$)");
//取這個元素的該行為 的 事件列表
handlers = (data(this, "events") || {} )[event.type];
//遍歷這個事件列表 執行該執行的東西
for ( var j in handlers ) {
var handler = handlers[j];
if ( all || namespace.test(handler.type) ) {
// Pass in a reference to the handler function itself
// So that we can later remove it
// jq上的注釋是是這么寫的 把event的handler 引用這個事件 方便之后移除
// 但是在remove里面 并沒有用到event的handler  不知道這里到底有什么用  且有多個事件的時候這個事件被取代
event.handler = handler;
//執行事件 并且是用元素調用的事件 可以吧事件里面的this執行元素 ret為函數的返回值
var ret = handler.apply(this, arguments);
//如果有返回值  且返回值是false 執行阻止事件冒泡 阻止執行事件默認行為
if( ret !== undefined ){
event.result = ret;
if ( ret === false ) {
event.preventDefault();
event.stopPropagation();
}
}
}
}
},
props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix : function(event){
//new setEvent會給event給以個expando屬性 如果有中個屬性 說明已經生成了event了 不需要在次對event進行包裝
if ( event[expando] )
return event;
//保留一個原始的event
// new一個新的event 這個與原始的event是不同的
var originalEvent = event;
event = new setEvent( originalEvent );
//獲得原始event的屬性值  有哪些屬性值 見 this.props
for ( var i = this.props.length, prop; i; ){
prop = this.props[ --i ];
event[ prop ] = originalEvent[ prop ];
}
//將目標元素同一成event.target
if ( !event.target )
event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
//如果發現是文本節點 取他的父節點
if ( event.target.nodeType == 3 )
event.target = event.target.parentNode;
if ( !event.relatedTarget && event.fromElement )
event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
return event;
}
}
win.setEvent = function(src){
// Allow instantiation without the 'new' keyword
// Event object
if( src && src.type ){
this.originalEvent = src;
this.type = src.type;
// Event type
}else
this.type = src;
// timeStamp is buggy for some events on Firefox(#3843)
// So we won't rely on the native value
this.timeStamp = now();
// Mark it as fixed
this[expando] = true;
}
function returnFalse(){
return false;
}
function returnTrue(){
return true;
}
setEvent.prototype = {
preventDefault: function() {
var e = this.originalEvent;
if( !e )
return;
// if preventDefault exists run it on the original event
if (e.preventDefault)
e.preventDefault();
// otherwise set the returnValue property of the original event to false (IE)
e.returnValue = false;
},
stopPropagation: function() {
var e = this.originalEvent;
if( !e )
return;
// if stopPropagation exists run it on the original event
if (e.stopPropagation)
e.stopPropagation();
// otherwise set the cancelBubble property of the original event to true (IE)
e.cancelBubble = true;
},
stopImmediatePropagation:function(){
this.isImmediatePropagationStopped = returnTrue;
this.stopPropagation();
},
isImmediatePropagationStopped: returnFalse
};
})(document);
var $ = function(id){return document.getElementById(id)}
var a = function(){alert(1)}
window.onload = function(){
gevent.add($('xx'),'click',a);
gevent.add($('xx'),'click',function(){alert(1)});
gevent.add($('xx'),'click',function(){alert(2)});
gevent.add($('xx'),'click',function(){alert(3)});
gevent.add($('xx'),'click.xx',function(){alert(4)});
}
</script>
</body>
</html>

 

 

 

以上內容只是自己的一些理解,水平有限,難免有錯,望指正...


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日本韩国在线不卡| 69国产精品成人在线播放| 亚洲天堂av综合网| 久久久久久网址| 国产精品激情av电影在线观看| 国产日韩欧美影视| 日韩av在线免播放器| 日本精品视频在线| 91精品久久久久| 日韩av一区二区在线观看| 欧美老少配视频| 亚洲国产精品久久| 欧美精品在线观看| 国产精品小说在线| 亚洲视频在线看| 日韩经典中文字幕| 亚洲一区二区三| 久久久久久有精品国产| 国产精品福利在线观看| 不卡在线观看电视剧完整版| 亚洲最新在线视频| 一区二区三区回区在观看免费视频| 久久久久久久久久国产| 国产精品视频久| 欧美人成在线视频| 亚洲欧美日韩综合| 草民午夜欧美限制a级福利片| 亚洲国产精品久久久久| 日韩精品在线看| 福利一区福利二区微拍刺激| 日韩在线观看av| 日韩中文在线中文网在线观看| 国产在线观看精品一区二区三区| 亚洲欧洲av一区二区| 中文字幕亚洲欧美一区二区三区| 国产精品6699| 国产精品第100页| 亚洲a级在线观看| 成人www视频在线观看| 欧美成人在线免费| 精品国产一区久久久| 亚洲影院污污.| 亚洲乱码一区二区| 91亚洲国产成人精品性色| 精品中文字幕在线观看| 清纯唯美亚洲综合| 久久精品中文字幕免费mv| 久久免费视频在线观看| 亚洲国产精品久久| 亚洲电影免费观看高清完整版在线观看| 亚洲free嫩bbb| 久久国产精品久久久久久久久久| 日韩精品在线免费观看视频| 中文字幕视频在线免费欧美日韩综合在线看| 久热99视频在线观看| 欧美激情视频在线免费观看 欧美视频免费一| 日韩女优在线播放| 国产精品免费观看在线| 日韩欧美高清在线视频| www.美女亚洲精品| 日韩免费视频在线观看| 亚洲最大成人免费视频| 成人欧美一区二区三区黑人孕妇| 精品成人av一区| 奇米成人av国产一区二区三区| 伊人久久男人天堂| 7777kkkk成人观看| 国产精品精品久久久久久| 国产亚洲精品久久久久久777| 91在线视频九色| 在线播放日韩精品| 国产成人精品国内自产拍免费看| 久久久久久国产| 亚洲性视频网站| 欧美日韩不卡合集视频| 日韩av电影在线网| 精品中文字幕久久久久久| 欧美日韩在线免费| 91久久夜色精品国产网站| 亚洲午夜女主播在线直播| 亚洲影院污污.| 日韩www在线| 欧美伦理91i| 91精品国产色综合| 欧美大成色www永久网站婷| 欧洲美女7788成人免费视频| 亚洲精品短视频| 国产精品成人免费视频| 日韩综合视频在线观看| 亚洲2020天天堂在线观看| 国产97在线观看| 欧美中文在线视频| 最近2019中文字幕在线高清| 国产成人精品综合久久久| 久热精品视频在线免费观看| 色综合亚洲精品激情狠狠| 91最新在线免费观看| 2019精品视频| 欧美裸体视频网站| 日韩免费视频在线观看| 欧美激情中文字幕乱码免费| 成人免费福利视频| 在线电影欧美日韩一区二区私密| 久久人人看视频| 国精产品一区一区三区有限在线| 社区色欧美激情 | 在线观看久久久久久| 成人激情在线观看| 午夜剧场成人观在线视频免费观看| 欧美孕妇孕交黑巨大网站| 久久天天躁狠狠躁夜夜躁| 神马久久桃色视频| 欧洲精品在线视频| 国内精品久久久久伊人av| 精品视频在线播放色网色视频| 国产成人jvid在线播放| 国产精品 欧美在线| 韩剧1988在线观看免费完整版| 欧美大胆在线视频| 亚洲国产成人在线播放| 欧美午夜xxx| 91av视频导航| 亚洲欧美精品一区| 亚洲精品国产精品国自产观看浪潮| 亚洲在线视频观看| 国产女人18毛片水18精品| 大伊人狠狠躁夜夜躁av一区| 亚洲美女激情视频| 亚洲无限乱码一二三四麻| 欧美日韩在线影院| 亚洲欧美中文日韩在线v日本| 91福利视频在线观看| 国产日韩专区在线| 国产一区香蕉久久| 狠狠色噜噜狠狠狠狠97| 北条麻妃99精品青青久久| 色婷婷综合成人av| 亚洲精品久久久久国产| 91久久国产精品91久久性色| 日韩欧美国产黄色| 精品日本美女福利在线观看| 日韩精品在线视频美女| 91国内免费在线视频| 欧美精品videos另类日本| 亚洲色图17p| 亚洲护士老师的毛茸茸最新章节| 国产精品久久久久77777| 国产精品视频不卡| 国产精品69久久| 中文字幕少妇一区二区三区| 日本三级久久久| 欧美一级视频一区二区| 国产原创欧美精品| 538国产精品视频一区二区| 亚洲国产婷婷香蕉久久久久久| 精品久久久久人成| 在线看福利67194| 岛国av一区二区三区| 日本欧美一二三区| 久久久视频在线| 国产性色av一区二区| 欧美午夜激情小视频| 亚洲精品一区二三区不卡| 国产成人在线一区|