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>
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; } }
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>
以上内容只是自己的一些理解,水平有限,难免有错,望指正...
本文向大家介绍浅谈Jquery为元素绑定事件,包括了浅谈Jquery为元素绑定事件的使用技巧和注意事项,需要的朋友参考一下 Jquery如何为元素绑定事件,小记一下,防止忘记了! 以上所述就是本文的全部内容了,希望大家能够喜欢。
本文向大家介绍浅谈jquery之on()绑定事件和off()解除绑定事件,包括了浅谈jquery之on()绑定事件和off()解除绑定事件的使用技巧和注意事项,需要的朋友参考一下 off()函数用于移除元素上绑定的一个或多个事件的事件处理函数。 off()函数主要用于解除由on()函数绑定的事件处理函数。 该函数属于jQuery对象(实例)。 语法 jQuery 1.7 新增该函数。其主要有以下两
本文向大家介绍浅谈jQuery的bind和unbind事件(绑定和解绑事件),包括了浅谈jQuery的bind和unbind事件(绑定和解绑事件)的使用技巧和注意事项,需要的朋友参考一下 绑定其实就是把一些常规时间绑定到页面,然后进行各种常规操作 解绑就是接触绑定,绑定的事件失效 要注意,iQuery中的 .事件 如(.click())其实就是单个的绑定事件的简写(bind("click"))
本文向大家介绍浅谈jquery事件处理,包括了浅谈jquery事件处理的使用技巧和注意事项,需要的朋友参考一下 在以jQuery为基础库的前端开发体系中,经常会在一个页面上通过各种标识绑定许许多多的事件。就算简单的使用了事件代理,也还是造成了事件的分散,不好维护和管理。 那么,如何解决这个问题呢?而我,想到了backbone中的events。如下: 也就是,把事件聚集到一起,类似事件处理中心这么一
本文向大家介绍浅谈jQuery中的事件,包括了浅谈jQuery中的事件的使用技巧和注意事项,需要的朋友参考一下 JQuery事件初见 1.JQuery中的事件绑定 其实呢,JQuery中标准的事件绑定是这样写下:(如下) 但是每次这样写,太过麻烦,还怎么做到Write less,Do more? 所以我们习惯的简写成。 $("#btn").click(function(){ }) 这样就方便了
本文向大家介绍浅谈Vue数据绑定的原理,包括了浅谈Vue数据绑定的原理的使用技巧和注意事项,需要的朋友参考一下 本文介绍了Vue数据绑定的原理,分享给大家,具体如下: 原理 其实原理很简单,就是拦截了Object的get/set方法,在对数据进行set (obj.aget=18) 时去重现渲染视图 实现方式有两种 方式1 定义了同名的get/set就相当于定义了age 为了让test不显示多余的变