- /*
- * author:prk
- * date:2008-08-17
- * comment:analyse of jquery event
- *
- */
- jQuery.event = {
- // add 事件到一个元素上。
- add : function(elem, types, handler, data) {
- if (elem.nodeType == 3 || elem.nodeType == 8)// 空白节点或注释
- return;
- // IE不能传入window,先复制一下。
- if (jQuery.browser.msie && elem.setInterval)
- elem = window;
- // 为handler分配一个全局唯一的Id
- if (!handler.guid)
- handler.guid = this.guid++;
- // 把data附到handler.data中
- if (data != undefined) {
- var fn = handler;
- handler = this.proxy(fn, function() {// 唯一Id,wrap原始handler Fn
- return fn.apply(this, arguments);
- });
- handler.data = data;
- }
- // 初始化元素的events。如果没有取到events中值,就初始化data: {}
- var events = jQuery.data(elem, "events")
- || jQuery.data(elem, "events", {}),
- // 如果没有取到handle中值,就初始化data: function() {....}
- handle = jQuery.data(elem, "handle")
- || jQuery.data(elem, "handle", function() {
- // 处理一个触发器的第二个事件和当page已经unload之后调用一个事件。
- if (typeof jQuery != "undefined"
- && !jQuery.event.triggered)
- return jQuery.event.handle.apply(// arguments.callee.elem=handle.elem
- arguments.callee.elem, arguments);
- });
- // 增加elem做为handle属性,防止IE由于没有本地Event而内存泄露。
- handle.elem = elem;
- // 处理采用空格分隔多个事件名,如jQuery(...).bind("mouseover mouseout", fn);
- jQuery.each(types.split(/\s+/), function(index, type) {
- // 命名空间的事件,一般不会用到。
- var parts = type.split(".");
- type = parts[0];
- handler.type = parts[1];
- // 捆绑到本元素type事件的所有处理函数
- var handlers = events[type];
- if (!handlers) {// 没有找到处理函数列表就初始化事件队列
- handlers = events[type] = {};
- // 如果type不是ready,或ready的setup执行返回false
- if (!jQuery.event.special[type]
- || jQuery.event.special[type].setup
- .call(elem, data) === false) {
- // 调用系统的事件函数来注册事件
- if (elem.addEventListener)// FF
- elem.addEventListener(type, handle, false);
- else if (elem.attachEvent)// IE
- elem.attachEvent("on" + type, handle);
- }
- }
- // 把处理器的id和handler形式属性对的形式保存在handlers列表中,
- // 也存在events[type][handler.guid]中。
- handlers[handler.guid] = handler;
- // 全局缓存这个事件的使用标识
- jQuery.event.global[type] = true;
- });
- // 防止IE内存泄露。
- elem = null;
- },
- guid : 1,
- global : {},
- // 从元素中remove一个事件
- remove : function(elem, types, handler) {
- if (elem.nodeType == 3 || elem.nodeType == 8)
- return;
- // 取出元素的events中Fn列表
- var events = jQuery.data(elem, "events"), ret, index;
- if (events) {
- // remove所有的该元素的事件 .是命名空间的处理
- if (types == undefined
- || (typeof types == "string" && types.charAt(0) == "."))
- for (var type in events)
- this.remove(elem, type + (types || ""));
- else {
- // types, handler参数采用{type:xxx,handler:yyy}形式
- if (types.type) {
- handler = types.handler;
- types = types.type;
- }
- // 处理采用空格分隔多个事件名 jQuery(...).unbind("mouseover mouseout", fn);
- jQuery
- .each(types.split(/\s+/), function(index, type) {
- // 命名空间的事件,一般不会用到。
- var parts = type.split(".");
- type = parts[0];
- if (events[type]) {// 事件名找到
- if (handler)// handler传入,就remove事件名的这个处理函数
- delete events[type][handler.guid];//guid的作用
- else // remove这个事件的所有处理函数,带有命名空间的处理
- for (handler in events[type])
- if (!parts[1]
- || events[type][handler].type == parts[1])
- delete events[type][handler];
- // 如果没有该事件的处理函数存在,就remove事件名
- for (ret in events[type])// 看看有没有?
- break;
- if (!ret) {// 没有
- if (!jQuery.event.special[type]//不是ready
- || jQuery.event.special[type].teardown
- .call(elem) === false) {// type不等于ready
- if (elem.removeEventListener)// 在浏览器中remove事件名
- elem.removeEventListener(type,
- jQuery.data(elem,
- "handle"),
- false);
- else if (elem.detachEvent)
- elem.detachEvent("on" + type,
- jQuery.data(elem,
- "handle"));
- }
- ret = null;
- delete events[type];// 在缓存中除去。
- }
- }
- });
- }
- // 不再使用,除去expando
- for (ret in events)
- break;
- if (!ret) {
- var handle = jQuery.data(elem, "handle");
- if (handle)
- handle.elem = null;
- jQuery.removeData(elem, "events");
- jQuery.removeData(elem, "handle");
- }
- }
- },
- trigger : function(type, data, elem, donative, extra) {
- data = jQuery.makeArray(data);
- if (type.indexOf("!") >= 0) {// 支持!的not的操作如!click,除click之后的所有
- type = type.slice(0, -1);// 除最后一个字符?
- var exclusive = true;
- }
- if (!elem) {// 处理全局的fire事件
- if (this.global[type])
- jQuery.each(jQuery.cache, function() {
- // 从cache中找到所有注册该事件的元素,触发改事件的处理函数
- if (this.events && this.events[type])
- jQuery.event.trigger(type, data, this.handle.elem);
- });
- } else {// 处理单个元素事件的fire事件
- if (elem.nodeType == 3 || elem.nodeType == 8)
- return undefined;
- var val, ret, fn = jQuery.isFunction(elem[type] || null),
- // 我们是否要提交一个伪造的事件?
- event = !data[0] || !data[0].preventDefault;
- // 构建伪造的事件。
- if (event) {
- data.unshift( {//存到数组中的第一个
- type : type,
- target : elem,
- preventDefault : function() {
- },
- stopPropagation : function() {
- },
- timeStamp : now()
- });
- data[0][expando] = true; // 不需要修正伪造事件
- }
- //防止事件名出错
- data[0].type = type;
- if (exclusive)
- data[0].exclusive = true;
- // 触发事件
- var handle = jQuery.data(elem, "handle");
- if (handle)
- val = handle.apply(elem, data);
- // Handle triggering native .onfoo handlers (and on links since we
- // don't call .click() for links)
- //处理触发.onfoo这样的本地处理方法,但是是对于links 's .click()不触发
- if ((!fn || (jQuery.nodeName(elem, 'a') && type == "click"))
- && elem["on" + type]&& elem["on" + type].apply(elem, data) === false)
- val = false;
- // Extra functions don't get the custom event object
- if (event)
- data.shift();
- // 处理触发extra事件
- if (extra && jQuery.isFunction(extra)) {
- //执行extra,同时把结果存到data中。
- ret = extra.apply(elem, val == null ? data : data.concat(val));
- // if anything is returned, give it precedence and have it
- // overwrite the previous value
- if (ret !== undefined)
- val = ret;
- }
- // 触发本地事件
- if (fn && donative !== false && val !== false
- && !(jQuery.nodeName(elem, 'a') && type == "click")) {
- this.triggered = true;
- try {
- elem[type]();
- //对于一些hidden的元素,IE会报错
- } catch (e) {
- }
- }
- this.triggered = false;
- }
- return val;
- },
- handle : function(event) {
- // 返回 undefined or false
- var val, ret, namespace, all, handlers;
- event = arguments[0] = jQuery.event.fix(event || window.event);
- // 命名空间处理
- namespace = event.type.split(".");
- event.type = namespace[0];
- namespace = namespace[1];
- // all = true 表明任何 handler
- all = !namespace && !event.exclusive;
- // 找到元素的events中缓存的事件名的处理函数列表
- handlers = (jQuery.data(this, "events") || {})[event.type];
- for (var j in handlers) {// 每个处理函数执行
- var handler = handlers[j];
- // Filter the functions by class
- if (all || handler.type == namespace) {
- // 传入引用,为了之后删除它们
- event.handler = handler;
- event.data = handler.data;
- ret = handler.apply(this, arguments);// 执行事件处理函数
- if (val !== false)
- val = ret;// 只要有一个处理函数返回false,本函数就返回false.
- if (ret === false) {// 不执行浏览器默认的动作
- event.preventDefault();
- event.stopPropagation();
- }
- }
- }
- return val;
- },
- 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 timeStamp toElement type view wheelDelta which"
- .split(" "),
- //对事件进行包裹。
- fix : function(event) {
- if (event[expando] == true)//表明事件已经包裹过
- return event;
- //保存原始event,同时clone一个。
- var originalEvent = event;
- event = {
- originalEvent : originalEvent
- };
- for (var i = this.props.length, prop;i;) {
- prop = this.props[--i];
- event[prop] = originalEvent[prop];
- }
- event[expando] = true;
- //加上preventDefault and stopPropagation,在clone不会运行
- event.preventDefault = function() {
- // 在原始事件上运行
- if (originalEvent.preventDefault)
- originalEvent.preventDefault();
- originalEvent.returnValue = false;
- };
- event.stopPropagation = function() {
- // 在原始事件上运行
- if (originalEvent.stopPropagation)
- originalEvent.stopPropagation();
- originalEvent.cancelBubble = true;
- };
- // 修正 timeStamp
- event.timeStamp = event.timeStamp || now();
- // 修正target
- if (!event.target)
- event.target = event.srcElement || document;
- if (event.target.nodeType == 3)//文本节点是父节点。
- event.target = event.target.parentNode;
- // relatedTarget
- if (!event.relatedTarget && event.fromElement)
- event.relatedTarget = event.fromElement == event.target
- ? event.toElement
- : event.fromElement;
- // Calculate pageX/Y if missing and clientX/Y available
- if (event.pageX == null && event.clientX != null) {
- var doc = document.documentElement, body = document.body;
- event.pageX = event.clientX
- + (doc && doc.scrollLeft || body && body.scrollLeft || 0)
- - (doc.clientLeft || 0);
- event.pageY = event.clientY
- + (doc && doc.scrollTop || body && body.scrollTop || 0)
- - (doc.clientTop || 0);
- }
- // Add which for key events
- if (!event.which
- && ((event.charCode || event.charCode === 0)
- ? event.charCode
- : event.keyCode))
- event.which = event.charCode || event.keyCode;
- // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
- if (!event.metaKey && event.ctrlKey)
- event.metaKey = event.ctrlKe
jQuery event 源码注释
最新推荐文章于 2019-02-27 09:05:23 发布