我正在研究一个跨浏览器的事件处理系统。我请一些开发人员审查我的代码。一位开发人员说我的实现是基于回调而不是真实事件。有什么区别?
为方便起见,我在下面提供了我的实现源代码(以及 as a gist )。到目前为止,我还没有发现任何问题。它适用于我测试过的所有浏览器。
对于问题的错误描述,我很抱歉,我不熟悉那个纯事件部分。
var evento = (function (window) {
var win = window
, doc = win.document
, _handlers = {}
, addEvent
, removeEvent
, triggerEvent;
addEvent = (function () {
if (typeof doc.addEventListener === "function") {
return function (el, evt, fn) {
el.addEventListener(evt, fn, false);
_handlers[el] = _handlers[el] || {};
_handlers[el][evt] = _handlers[el][evt] || [];
_handlers[el][evt].push(fn);
};
} else if (typeof doc.attachEvent === "function") {
return function (el, evt, fn) {
el.attachEvent(evt, fn);
_handlers[el] = _handlers[el] || {};
_handlers[el][evt] = _handlers[el][evt] || [];
_handlers[el][evt].push(fn);
};
} else {
return function (el, evt, fn) {
el["on" + evt] = fn;
_handlers[el] = _handlers[el] || {};
_handlers[el][evt] = _handlers[el][evt] || [];
_handlers[el][evt].push(fn);
};
}
}());
// removeEvent
removeEvent = (function () {
if (typeof doc.removeEventListener === "function") {
return function (el, evt, fn) {
el.removeEventListener(evt, fn, false);
Helio.each(_handlers[el][evt], function (fun) {
if (fun === fn) {
_handlers[el] = _handlers[el] || {};
_handlers[el][evt] = _handlers[el][evt] || [];
_handlers[el][evt][_handlers[el][evt].indexOf(fun)] = undefined;
}
});
};
} else if (typeof doc.detachEvent === "function") {
return function (el, evt, fn) {
el.detachEvent(evt, fn);
Helio.each(_handlers[el][evt], function (fun) {
if (fun === fn) {
_handlers[el] = _handlers[el] || {};
_handlers[el][evt] = _handlers[el][evt] || [];
_handlers[el][evt][_handlers[el][evt].indexOf(fun)] = undefined;
}
});
};
} else {
return function (el, evt, fn) {
el["on" + evt] = undefined;
Helio.each(_handlers[el][evt], function (fun) {
if (fun === fn) {
_handlers[el] = _handlers[el] || {};
_handlers[el][evt] = _handlers[el][evt] || [];
_handlers[el][evt][_handlers[el][evt].indexOf(fun)] = undefined;
}
});
};
}
}());
// triggerEvent
triggerEvent = function (el, evt) {
_handlers[el] = _handlers[el] || {};
_handlers[el][evt] = _handlers[el][evt] || [];
for (var _i = 0, _l = _handlers[el][evt].length; _i < _l; _i += 1) {
_handlers[el][evt][_i]();
}
};
return {
add: addEvent,
remove: removeEvent,
trigger: triggerEvent,
_handlers: _handlers
};
}(this));
最佳答案
我一点也不在乎你的系统是基于回调、事件或 lambda 演算的。对于您在此处公开的部分,它似乎写得相当好并且有望做得很好(尽管我很好奇您如何处理 removeEvent()
;))。
但是,我对您的实现有几点评论:
- 无需在每次添加事件处理程序时检查您在哪个浏览器上执行。
令我惊讶的是,有这么多人接受每次调用时检查属性是否存在的做法。没有人会在函数调用的中间将您的 IE 换成 FF(并且任何愚蠢到定义 document.addEventListener
属性而不是实际 ECMA-5 替换的人都应该被鞭打死,如果你问我),所以在开始时检查你在哪个平台上并完成它,就像这样:
if (doc.addEventListener) {
addEvent = // ...
freeEvent = // ...
}
else if (doc.attachEvent) {
addEvent = // ...
freeEvent = // ...
}
/* etc. */
- 您提供了一个统一的接口(interface)来附加处理程序,但是,根据您的代码将在其上执行的浏览器,实际处理程序的行为会有所不同。
例如,在 IE8 中,事件目标的可用方式与 ECMA-5 约定不同。
如果你想提供一个真正的跨浏览器界面,你应该为事件处理程序提供一个统一的执行上下文。 这可能包括一个“取消”功能,该功能将转换为类似以下内容:
cancel = function (e) { e.returnValue = false; }; // IE8-
cancel = function (e) { e.preventDefault(); }; // ECMA-5
还应该将this
还原为IE8-下的target对象,统一target
和event.target
语义。
如果你真的想对程序员好一点,你也可以解决一些奇怪的问题,比如
- 加载事件不会在 IE8 中触发 - 当图像已被缓存时
- 极其复杂的鼠标滚轮报告系统
可能还有其他一些。
出于我自己的目的,我这样做的方法是在实际处理程序周围生成一个包装器,它可以处理所有平台特性并在调用实际用户代码之前建立一致的执行上下文。
最后的评论:除了它的美感,我不太确定它是否仍然有必要支持 Netscape4 风格的事件。但这是信仰问题,所以...
关于javascript - 基于回调和基于事件的事件处理系统有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19396182/