代码如下:
//对事件进行包裹。
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
if (!event.metaKey && event.ctrlKey) ⑧
event.metaKey = event.ctrlKey;
// Add which for click: 1 == left; 2 == middle; 3 == right
// Note: button is not normalized, so don't use it
if (!event.which && event.button) ⑨
event.which = (event.button & 1 ? 1 : (event.button & 2
? 3 : (event.button & 4 ? 2 : 0)));
return event;
},
代码如下:
bind : function(type, data, fn) {
return type == "unload" ? this.one(type, data, fn) : this
.each(function() {// fn || data, fn && data实现了data参数可有可无
jQuery.event.add(this, type, fn || data, fn && data);
}); },
代码如下:
one : function(type, data, fn) {
var One= jQuery.event.proxy(fn || data, function(event) {
jQuery(this).unbind(event, one);
return (fn || data).apply(this, arguments);/this->当前的元素
});
return this.each(function() {
jQuery.event.add(this, type, one, fn && data);
});
},
代码如下:
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(){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(//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)elem.addEventListener(type,handle,false);
else if (elem.attachEvent)elem.attachEvent("on" + type, handle);
}
}
// 把处理器的id和handler形式属性对的形式保存在handlers列表中,
// 也存在events[type][handler.guid]中。
handlers[handler.guid] = handler; ⑦
// 全局缓存这个事件的使用标识
jQuery.event.global[type] = true;
});
elem = null; // 防止IE内存泄露。
},
guid : 1,
global : {},
代码如下:
trigger : function(type, data, fn) {
return this.each(function() {
jQuery.event.trigger(type, data, this, true, fn);
}); },
代码如下:
trigger : function(type, data, elem, donative, extra) {
data = jQuery.makeArray(data);//data可以为{xx:yy}
//支持getData!这样的形式,exclusive = true表现会对add的注册的
//事件的所有函数进行命名空间的分种类的来执行。
if (type.indexOf("!") >= 0) { ①
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),
// 如果data参数传进入的不是浏览器的event对象的话,event变量为true.
//如果data参数本身是娄组,那么第一个元素不是 浏览器的event对象时为true.
//对于event为true。即没有event传进入,先构建一个伪造的event对象存在 data[0]。
event = !data[0] || !data[0].preventDefault;
// 在没有传入event对象的情况下,构建伪造event对象。
if (event) {//存到数组中的第一个 ④
data.unshift( { type : type,target : elem,
preventDefault : function() {},stopPropagation :
function() {}, timeStamp : now() });
data[0][expando] = true; // 不需要修正伪造的event对象
}
data[0].type = type; //防止事件名出错
//表现会进行事件注册函数的分类(命名空间)执行。不是所有的。
if (exclusive) data[0].exclusive = true;
//与prototype等传统的处理 方式不一样,没有采用fireEvent来
//来fire通过注册到浏览器事件中的事件处理方法。
//这里分了三步,先fire 通过jQuery.event.add来注册的事件,这个事件
//有可能是自定义的事件(没有注册到浏览器事件中)。
//第二步 是fire通过elem.onclick方式注册的事件的本地处理函数
//第三步是fire默认的事件处理方式(在本地的onclick的方式注册
//不存在的情况下)。
// 这里是触发通过jQuery.event.add来注册的事件,
var handle = jQuery.data(elem, "handle"); ⑤
if (handle)val = handle.apply(elem, data); //这里data分成多个参数
//处理触发通过elem.Onfoo=function()这样的注册本地处理方法,
//但是是 对于links 's .click()不触发,这个不会执行通过addEvent
//方式注册的事件处理方式。
if ((!fn || (jQuery.nodeName(elem, 'a') && type == "click")) ⑥
&& elem["on"+ type]&& elem["on"+type].apply(elem,data) === false)
val = false;
//额外的函 数参数的开始几个是通过data给定的。这里会把伪造加上的event给去掉。
//它的最后一个参数是一系列的事件处理函数返回的结果,一般为 bool值
//这个函数可以根据这个结果来处理一个扫尾的工作。
if (event) data.shift();
// 处理触发extra给定的函数处理。
if (extra && jQuery.isFunction(extra)) { ⑦
ret = extra.apply(elem, val == null ? data : data.concat(val));
//如果这个函数有返回值,那么trigger的返回值就是它的返回值
//没有的 话就是串连的事件处理函数的最后一个返回值。一般为bool
if (ret !== undefined) val = ret;
}
// 触发默认本地事件方法,它是在没有如.onclick注册事件
//加上前面的执行事件处理函数返回值都不为 false的情况下,才会执行。
//它还可以通donative来控制是否执行。
//如form中可以采用 this.submit()来提交form.
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,namespace不存在,同时
//event.exclusive不存在或为假时,all=true.
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;//add的时候加上的
ret = handler.apply(this, arguments);// 执行事件处理函数
if (val !== false)
val = ret;// 只要有一个处理函数返回false,本函数就返回false.
if (ret === false) {// 不执行浏览器默认的动作
event.preventDefault();
event.stopPropagation();
}
}
}
return val; }