浅谈jQuery事件绑定原理

2019-07-23 07:01栏目:WRB前端

jq里面有一个data的法子,给dom成分绑定相关的数量的。当给dom用jq的点子绑定了风云,会变动对应的光阴列表
能够看上面包车型客车事例(请在firefox中查看 因为firefox中指标扶助toSource())

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=">
<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>

<!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=";
<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的小时戳
此间要证澳优(Ausnutria Hyproca)下,有贰个uuid 他是拉长的
jQueryxxx的值正是以此uuid
cache 的 key就是其一 uuid
value正是要存的数码
data对于事件的绑定是比较重大的................................

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]; 
    } 
}

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.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);
});

 
随着达成增进事件

复制代码 代码如下:

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 = {
    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;

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 set伊夫nt会给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 ];
        }
        //将指标成分同10%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
};   

//这里的........
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 set伊夫nt会给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" "">
<html xmlns="">
<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] ) {
//借使传了首个参数 函数  则删除那几个事件
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 set伊夫nt会给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 ];
}
//将目的成分同10%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>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ";
<html xmlns=";
<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] ) {
//如若传了第三个参数 函数 则删除那么些事件
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>

以上内容只是本人的有的通晓,水平有限,难免有错,望指正...

能够看上边包车型地铁例子(请在firefox中查...

你只怕感兴趣的篇章:

  • jQuery事件绑定.on()简要概述及使用
  • 至于jQuery新的事件绑定机制on()的运用才干
  • jQuery事件绑定和寄托实例
  • jQuery事件绑定on()、bind()与delegate() 方法详解
  • jQuery文本框(input textare)事件绑定方法教程
  • jQuery达成开关只点击贰次后就收回点击事件绑定的章程
  • 分析jQuery的两种bind/One/Live事件绑定使用办法
  • jquery 新建的因素事件绑定难点一蹴而就方案
  • jQuery事件绑定与解除绑定达成格局
  • JQuery中DOM事件绑定用法详解
  • jQuery事件绑定用法详解(附bind和live的区分)
  • jQuery达成的风云绑定成效为主示例

版权声明:本文由威尼斯人app发布于WRB前端,转载请注明出处:浅谈jQuery事件绑定原理