`
liuwei_blog
  • 浏览: 94925 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

jQuery event 源码注释

阅读更多
  1. /*
  2.  * author:prk
  3.  * date:2008-08-17
  4.  * comment:analyse of jquery event
  5.  * 
  6.  */
  7. jQuery.event = {
  8.     // add 事件到一个元素上。
  9.     add : function(elem, types, handler, data) {
  10.         if (elem.nodeType == 3 || elem.nodeType == 8)// 空白节点或注释
  11.             return;
  12.         // IE不能传入window,先复制一下。
  13.         if (jQuery.browser.msie && elem.setInterval)
  14.             elem = window;
  15.         // 为handler分配一个全局唯一的Id
  16.         if (!handler.guid)
  17.             handler.guid = this.guid++;
  18.         // 把data附到handler.data中
  19.         if (data != undefined) {
  20.             var fn = handler;
  21.             handler = this.proxy(fn, function() {// 唯一Id,wrap原始handler Fn
  22.                         return fn.apply(this, arguments);
  23.                     });
  24.             handler.data = data;
  25.         }
  26.         // 初始化元素的events。如果没有取到events中值,就初始化data: {}
  27.         var events = jQuery.data(elem, "events")
  28.                 || jQuery.data(elem, "events", {}),
  29.         // 如果没有取到handle中值,就初始化data: function() {....}
  30.         handle = jQuery.data(elem, "handle")
  31.                 || jQuery.data(elem, "handle"function() {
  32.                     // 处理一个触发器的第二个事件和当page已经unload之后调用一个事件。
  33.                         if (typeof jQuery != "undefined"
  34.                                 && !jQuery.event.triggered)
  35.                             return jQuery.event.handle.apply(// arguments.callee.elem=handle.elem
  36.                                     arguments.callee.elem, arguments);
  37.                     });
  38.         // 增加elem做为handle属性,防止IE由于没有本地Event而内存泄露。
  39.         handle.elem = elem;
  40.         // 处理采用空格分隔多个事件名,如jQuery(...).bind("mouseover mouseout", fn);
  41.         jQuery.each(types.split(/\s+/), function(index, type) {
  42.             // 命名空间的事件,一般不会用到。
  43.                 var parts = type.split(".");
  44.                 type = parts[0];
  45.                 handler.type = parts[1];
  46.                 // 捆绑到本元素type事件的所有处理函数
  47.                 var handlers = events[type];
  48.                 if (!handlers) {// 没有找到处理函数列表就初始化事件队列
  49.                     handlers = events[type] = {};
  50.                     // 如果type不是ready,或ready的setup执行返回false
  51.                     if (!jQuery.event.special[type]
  52.                             || jQuery.event.special[type].setup
  53.                                     .call(elem, data) === false) {
  54.                         // 调用系统的事件函数来注册事件
  55.                         if (elem.addEventListener)// FF
  56.                             elem.addEventListener(type, handle, false);
  57.                         else if (elem.attachEvent)// IE
  58.                             elem.attachEvent("on" + type, handle);
  59.                     }
  60.                 }
  61.                 // 把处理器的id和handler形式属性对的形式保存在handlers列表中,
  62.                 // 也存在events[type][handler.guid]中。
  63.                 handlers[handler.guid] = handler;
  64.                 // 全局缓存这个事件的使用标识
  65.                 jQuery.event.global[type] = true;
  66.             });
  67.         // 防止IE内存泄露。
  68.         elem = null;
  69.     },
  70.     guid : 1,
  71.     global : {},
  72.     // 从元素中remove一个事件
  73.     remove : function(elem, types, handler) {
  74.         if (elem.nodeType == 3 || elem.nodeType == 8)
  75.             return;
  76.         // 取出元素的events中Fn列表
  77.         var events = jQuery.data(elem, "events"), ret, index;
  78.         if (events) {
  79.             // remove所有的该元素的事件 .是命名空间的处理
  80.             if (types == undefined
  81.                     || (typeof types == "string" && types.charAt(0) == "."))
  82.                 for (var type in events)
  83.                     this.remove(elem, type + (types || ""));
  84.             else {
  85.                 // types, handler参数采用{type:xxx,handler:yyy}形式
  86.                 if (types.type) {
  87.                     handler = types.handler;
  88.                     types = types.type;
  89.                 }
  90.                 // 处理采用空格分隔多个事件名 jQuery(...).unbind("mouseover mouseout", fn);
  91.                 jQuery
  92.                         .each(types.split(/\s+/), function(index, type) {
  93.                             // 命名空间的事件,一般不会用到。
  94.                                 var parts = type.split(".");
  95.                                 type = parts[0];
  96.                                 if (events[type]) {// 事件名找到
  97.                                     if (handler)// handler传入,就remove事件名的这个处理函数
  98.                                         delete events[type][handler.guid];//guid的作用
  99.                                     else    // remove这个事件的所有处理函数,带有命名空间的处理
  100.                                         for (handler in events[type])
  101.                                             if (!parts[1]
  102.                                                     || events[type][handler].type == parts[1])
  103.                                                 delete events[type][handler];
  104.                                     // 如果没有该事件的处理函数存在,就remove事件名
  105.                                     for (ret in events[type])// 看看有没有?
  106.                                         break;
  107.                                     if (!ret) {// 没有
  108.                                         if (!jQuery.event.special[type]//不是ready
  109.                                                 || jQuery.event.special[type].teardown
  110.                                                         .call(elem) === false) {// type不等于ready
  111.                                             if (elem.removeEventListener)// 在浏览器中remove事件名
  112.                                                 elem.removeEventListener(type,
  113.                                                         jQuery.data(elem,
  114.                                                                 "handle"),
  115.                                                         false);
  116.                                             else if (elem.detachEvent)
  117.                                                 elem.detachEvent("on" + type,
  118.                                                         jQuery.data(elem,
  119.                                                                 "handle"));
  120.                                         }
  121.                                         ret = null;
  122.                                         delete events[type];// 在缓存中除去。
  123.                                     }
  124.                                 }
  125.                             });
  126.             }
  127.             // 不再使用,除去expando
  128.             for (ret in events)
  129.                 break;
  130.             if (!ret) {
  131.                 var handle = jQuery.data(elem, "handle");
  132.                 if (handle)
  133.                     handle.elem = null;
  134.                 jQuery.removeData(elem, "events");
  135.                 jQuery.removeData(elem, "handle");
  136.             }
  137.         }
  138.     },
  139.     trigger : function(type, data, elem, donative, extra) {
  140.         data = jQuery.makeArray(data);
  141.         if (type.indexOf("!") >= 0) {// 支持!的not的操作如!click,除click之后的所有
  142.             type = type.slice(0, -1);// 除最后一个字符?
  143.             var exclusive = true;
  144.         }
  145.         if (!elem) {// 处理全局的fire事件
  146.             if (this.global[type])
  147.                 jQuery.each(jQuery.cache, function() {
  148.                     // 从cache中找到所有注册该事件的元素,触发改事件的处理函数
  149.                         if (this.events && this.events[type])
  150.                             jQuery.event.trigger(type, data, this.handle.elem);
  151.                     });
  152.         } else {// 处理单个元素事件的fire事件
  153.             if (elem.nodeType == 3 || elem.nodeType == 8)
  154.                 return undefined;
  155.             var val, ret, fn = jQuery.isFunction(elem[type] || null),
  156.             // 我们是否要提交一个伪造的事件?
  157.             event = !data[0] || !data[0].preventDefault;
  158.             // 构建伪造的事件。
  159.             if (event) {
  160.                 data.unshift( {//存到数组中的第一个
  161.                     type : type,
  162.                     target : elem,
  163.                     preventDefault : function() {
  164.                     },
  165.                     stopPropagation : function() {
  166.                     },
  167.                     timeStamp : now()
  168.                 });
  169.                 data[0][expando] = true// 不需要修正伪造事件
  170.             }
  171.             //防止事件名出错
  172.             data[0].type = type;
  173.             if (exclusive)
  174.                 data[0].exclusive = true;
  175.             // 触发事件
  176.             var handle = jQuery.data(elem, "handle");
  177.             if (handle)
  178.                 val = handle.apply(elem, data);
  179.             // Handle triggering native .onfoo handlers (and on links since we
  180.             // don't call .click() for links)
  181.             //处理触发.onfoo这样的本地处理方法,但是是对于links 's .click()不触发
  182.             if ((!fn || (jQuery.nodeName(elem, 'a') && type == "click"))
  183.                     && elem["on" + type]&& elem["on" + type].apply(elem, data) === false)
  184.                 val = false;
  185.             // Extra functions don't get the custom event object
  186.             if (event)
  187.                 data.shift();
  188.             // 处理触发extra事件
  189.             if (extra && jQuery.isFunction(extra)) {
  190.                 //执行extra,同时把结果存到data中。
  191.                 ret = extra.apply(elem, val == null ? data : data.concat(val));
  192.                 // if anything is returned, give it precedence and have it
  193.                 // overwrite the previous value
  194.                 if (ret !== undefined)
  195.                     val = ret;
  196.             }
  197.             // 触发本地事件
  198.             if (fn && donative !== false && val !== false
  199.                     && !(jQuery.nodeName(elem, 'a') && type == "click")) {
  200.                 this.triggered = true;
  201.                 try {
  202.                     elem[type]();
  203.                     //对于一些hidden的元素,IE会报错
  204.                 } catch (e) {
  205.                 }
  206.             }
  207.             this.triggered = false;
  208.         }
  209.         return val;
  210.     },
  211.     handle : function(event) {
  212.         // 返回 undefined or false
  213.         var val, ret, namespace, all, handlers;
  214.         event = arguments[0] = jQuery.event.fix(event || window.event);
  215.         // 命名空间处理
  216.         namespace = event.type.split(".");
  217.         event.type = namespace[0];
  218.         namespace = namespace[1];
  219.         // all = true 表明任何 handler
  220.         all = !namespace && !event.exclusive;
  221.         // 找到元素的events中缓存的事件名的处理函数列表
  222.         handlers = (jQuery.data(this"events") || {})[event.type];
  223.         for (var j in handlers) {// 每个处理函数执行
  224.             var handler = handlers[j];
  225.             // Filter the functions by class
  226.             if (all || handler.type == namespace) {
  227.                 // 传入引用,为了之后删除它们
  228.                 event.handler = handler;
  229.                 event.data = handler.data;
  230.                 ret = handler.apply(this, arguments);// 执行事件处理函数
  231.                 if (val !== false)
  232.                     val = ret;// 只要有一个处理函数返回false,本函数就返回false.
  233.                 if (ret === false) {// 不执行浏览器默认的动作
  234.                     event.preventDefault();
  235.                     event.stopPropagation();
  236.                 }
  237.             }
  238.         }
  239.         return val;
  240.     },
  241.     props : "altKey attrChange attrName bubbles button cancelable charCode clientX "
  242.             + "clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode "
  243.             + "metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX "
  244.             + "screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which"
  245.                     .split(" "),
  246.     //对事件进行包裹。
  247.     fix : function(event) {
  248.         if (event[expando] == true)//表明事件已经包裹过
  249.             return event;
  250.         //保存原始event,同时clone一个。
  251.         var originalEvent = event;
  252.         event = {
  253.             originalEvent : originalEvent
  254.         };
  255.         for (var i = this.props.length, prop;i;) {
  256.             prop = this.props[--i];
  257.             event[prop] = originalEvent[prop];
  258.         }
  259.         
  260.         event[expando] = true;
  261.         
  262.         //加上preventDefault and stopPropagation,在clone不会运行
  263.         event.preventDefault = function() {
  264.             // 在原始事件上运行
  265.             if (originalEvent.preventDefault)
  266.                 originalEvent.preventDefault();
  267.             
  268.             originalEvent.returnValue = false;
  269.         };
  270.         event.stopPropagation = function() {
  271.             // 在原始事件上运行
  272.             if (originalEvent.stopPropagation)
  273.                 originalEvent.stopPropagation();
  274.             
  275.             originalEvent.cancelBubble = true;
  276.         };
  277.         // 修正 timeStamp
  278.         event.timeStamp = event.timeStamp || now();
  279.         // 修正target
  280.         if (!event.target)
  281.             event.target = event.srcElement || document;            
  282.         if (event.target.nodeType == 3)//文本节点是父节点。
  283.             event.target = event.target.parentNode;
  284.         // relatedTarget
  285.         if (!event.relatedTarget && event.fromElement)
  286.             event.relatedTarget = event.fromElement == event.target
  287.                     ? event.toElement
  288.                     : event.fromElement;
  289.         // Calculate pageX/Y if missing and clientX/Y available
  290.         if (event.pageX == null && event.clientX != null) {
  291.             var doc = document.documentElement, body = document.body;
  292.             event.pageX = event.clientX
  293.                     + (doc && doc.scrollLeft || body && body.scrollLeft || 0)
  294.                     - (doc.clientLeft || 0);
  295.             event.pageY = event.clientY
  296.                     + (doc && doc.scrollTop || body && body.scrollTop || 0)
  297.                     - (doc.clientTop || 0);
  298.         }
  299.         // Add which for key events
  300.         if (!event.which
  301.                 && ((event.charCode || event.charCode === 0)
  302.                         ? event.charCode
  303.                         : event.keyCode))
  304.             event.which = event.charCode || event.keyCode;
  305.         // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
  306.         if (!event.metaKey && event.ctrlKey)
  307.             event.metaKey = event.ctrlKe
分享到:
评论

相关推荐

    jQuery源码详细分析中文注释

    《jQuery源码详细分析中文注释》是一份深入解析jQuery库源码的宝贵资源,它为开发者提供了理解这个广泛使用的JavaScript库内部工作机制的机会。jQuery以其简洁的API和强大的功能深受前端开发者的喜爱,但其背后的...

    jQuery 教程 源码+实例+注释

    **jQuery 教程 源码+实例+注释** jQuery 是一个广泛应用于网页开发的JavaScript库,它简化了HTML文档遍历、事件处理、动画设计以及Ajax交互。本教程针对初学者,旨在通过源码、实例和详尽的注释帮助你快速掌握...

    jQuery 教程 源码+实例+注释 [新手入门提高速成]

    **jQuery 教程 源码+实例+注释 [新手入门提高速成]** ...通过这个教程,你将全面了解 jQuery 的基本概念,掌握其核心功能,并通过实例和源码注释深入理解其实现机制。不断实践和探索,你将在 jQuery 领域更进一步。

    JQuery实现鼠标拖动元素移动位置(源码+注释)

    以下是完整的JavaScript代码示例,包括源码和注释: ```javascript $(document).ready(function() { // 当鼠标按下时,开始拖动 $("#draggable").mousedown(function(event) { // 记录鼠标按下时的位置 var ...

    jQuery实现的网页版打砖块小游戏源码.zip

    《jQuery实现的网页版打砖块小游戏源码分析》 jQuery是一个广泛应用于Web开发的JavaScript库,它简化了HTML文档遍历、事件处理、...实际应用中,开发者还需要阅读源码并根据注释理解代码逻辑,以便进一步学习和改进。

    基于jQuery实现模仿京东侧边购物车菜单特效源码.zip

    "基于jQuery实现模仿京东侧边购物车菜单特效源码"这个标题指出,这是一个关于前端开发的项目,特别关注于使用jQuery库来创建一个与京东网站相似的侧边购物车菜单的动画效果。jQuery是一个广泛使用的JavaScript库,它...

    jquery-1.3.2.min.js

    - **jQuery源码阅读**:理解.min.js背后的源码逻辑,有助于深入学习JavaScript和前端开发。 总之,jQuery 1.3.2.min.js作为一款经典的JavaScript库,不仅简化了DOM操作,还带来了丰富的动画效果和便捷的AJAX功能,...

    jQuery实现的360浏览器九宫格图片拖拽排序特效源码.zip

    1. **事件监听**:jQuery提供了便捷的事件绑定方法,如`$(element).on('event', callback)`,在这个案例中,可能使用了`mousedown`、`mousemove`和`mouseup`事件来追踪用户的鼠标操作,实现拖拽的开始、进行和结束。...

    jquery 资源库

    - **事件处理(Event Handling)**:jQuery简化了事件绑定,如`$("button").click(function() {...})`监听按钮点击事件。 - **动画效果(Animation)**:`fadeIn()`, `slideToggle()`, `animate()`等方法使创建...

    jQuery实现的点击链接后弹出窗口背景阴暗遮罩效果源码.zip

    "使用须知.txt"文件可能包含了关于如何在自己的项目中集成和使用这些源码的说明,而"132689909636681178"可能是具体的源码文件,可能包含更详细的实现和注释。通过研究这些文件,你可以更深入地了解这个功能的实现...

    jQuery编写的推箱子

    《jQuery编写的推箱子》是一款基于JavaScript库jQuery开发的在线推箱子游戏,它以其独特的编程...通过深入研究源码和注释,开发者可以了解到如何利用jQuery实现一个完整的交互式应用,同时也可以体会到游戏设计的乐趣。

    jquery

    jQuery源码组织清晰,注释详尽,是学习JavaScript设计模式和优化技巧的好材料。例如,它的选择器引擎Sizzle,以及事件处理和动画实现都是值得研究的部分。 **八、工具与框架** jQuery还发展出一系列工具和框架,如...

    jquery3.4.1压缩版和未压缩版

    未压缩版(通常称为源码版)是供开发者阅读和调试用的,代码未经过混淆和压缩,保留了原始的注释和变量名,方便理解内部工作原理。在开发阶段,使用未压缩版有助于调试和定位问题。 压缩版(通常称为生产版)则是...

    jquery教程及

    **jQuery教程及源码解析** jQuery是一个广泛应用于前端开发的JavaScript库,它的出现极大地简化了JavaScript的DOM操作、事件处理...结合提供的源码、实例和注释,您将能更好地理解和运用jQuery,成为前端开发的高手。

    jquery-2.0.3.min.js.pdf

    接下来的代码是压缩后的JavaScript代码,包含了jQuery的核心实现,由于是压缩版,直接阅读理解较为困难,通常会在开发环境中引用未压缩的源码。 `x.fn.init`是jQuery构造函数的初始化方法,用于创建jQuery对象。`x....

    读jQuery之七 判断点击了鼠标哪个键的代码

    然而,值得注意的是,尽管jQuery的源码中有关于`event.which`处理鼠标的注释,但在jQuery文档中,`event.which`主要被描述为适用于键盘事件,并没有明确提及鼠标事件。实际上,`event.which`在`click`事件中可能无法...

    MyRead:jQuery源代码的阅读

    《MyRead:深入理解jQuery源码》 在IT领域,jQuery是一个不可或缺的JavaScript库,它极大地简化了DOM操作、事件处理、动画制作等任务。本文将基于“MyRead”项目,详细探讨对jQuery源代码的阅读与理解,帮助开发者...

    读jQuery之十一 添加事件核心方法

    在jQuery.event.add方法的源码中,首先检查elem是否为文本节点或注释节点,这两种类型的节点不会执行事件绑定,因此会直接返回。随后,如果handler参数为false,jQuery将handler赋值为一个预定义的returnFalse函数,...

    小程序各大效果实现列子

    fullpage是jquery的插件库jquery.fullpage.js,里面是一个应用于移动端的小项目,rem布局 + fullpage页面滑动 js_event是将所有事件的知识点写成Demo,包括浏览器兼容 mochaDemo 是mocha单元测试使用demo es6-...

Global site tag (gtag.js) - Google Analytics