IE与非IE浏览器在事件绑定的执行顺序问题
2009-09-21 00:00:00 来源:WEB开发网原始的DOM1事件处理机制,是不能绑定多个处理函数。如一个元素在onclick事件先绑定一个函数,用来alert其id,然后再在相同的事件绑定另一个函数,用来alert其style。对不起,第二个函数会覆盖掉第一个,只会alert其style。于是.addEventListener() 与 .attachEvent()被分别开发出来了。为了屏蔽各浏览器的差异,javascript界举办了一个慈善邀请赛,鼓励大家提交各自 addEvent/removeEvent 方案,最后由John Resig大神获得。
01.function addEvent( obj, type, fn ) {
02. if ( obj.attachEvent ) {
03. obj["e"+type+fn] = fn;
04. obj[type+fn] = function(){obj["e"+type+fn]( window.event );}
05. obj.attachEvent("on"+type, obj[type+fn] );
06. } else
07. obj.addEventListener( type, fn, false );
08.}
09.function removeEvent( obj, type, fn ) {
10. if ( obj.detachEvent ) {
11. obj.detachEvent("on"+type, obj[type+fn] );
12. obj[type+fn] = null;
13. } else
14. obj.removeEventListener( type, fn, false );
15.}
但是最近我在同一个元素绑定多个onclick事件时,发现些问题。
但是最近我在同一个元素绑定多个onclick事件时,发现些问题。
[Ctrl+A 全部选择 提示:你可先修改部分代码,再按运行]
IE8与其他标准浏览器会弹出1,2,3,4,换言之,先进先出。IE6非先进先出,也不是后进先出,而是2,4,3,1。这是一个比较寒心的问题。我开始以为IE在调用元素自定义属性["e"+type+fn] 上存在问题(我们可以用IE8的开发人员工具看到这些冗长的属性),于是对John Resig的函数进行升级(不依赖于自定义属性):
1.var addEvent = function( obj, type, fn ) {
2. if (!+"\v1") {
3. var _fn = function(){fn.call(obj,window.event)}
4. obj.attachEvent("on"+type,_fn);
5. }else {
6. obj.addEventListener(type, fn, false);
7. }
8.};
发现没有用,于是google一下,收获甚丰。有人把W3C的事件模型弄出了个IE版,只是代码长了一点。
001. /**
002. * addEvent & removeEvent -- cross-browser event handling
003. * Copyright (C) 2006-2007 Dao Gottwald
004. *
005. * This library is free software; you can redistribute it and/or
006. * modify it under the terms of the GNU Lesser General Public
007. * License as published by the Free Software Foundation; either
008. * version 2.1 of the License, or (at your option) any later version.
009. *
010. * This library is distributed in the hope that it will be useful,
011. * but WITHOUT ANY WARRANTY; without even the implied warranty of
012. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013. * Lesser General Public License for more details.
014. *
015. * You should have received a copy of the GNU Lesser General Public
016. * License along with this library; if not, write to the Free Software
017. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
018. *
019. * Contact information:
020. * Dao Gottwald <dao at design-noir.de>
021. *
022. * @version 1.2.1
023. */
024.
025. function addEvent(o, type, fn) {
026. o.addEventListener(type, fn, false);
027. }
028. function removeEvent(o, type, fn) {
029. o.removeEventListener(type, fn, false);
030. }
031. /*@cc_on if (!window.addEventListener) {
032. var addEvent = function (o, type, fn) {
033. if (!o._events) o._events = {};
034. var queue = o._events[type];
035. if (!queue) {
036. o._events[type] = [fn];
037. if (!o._events._callback)
038. o._events._callback = function (e) { Event._callListeners(e, o) };
039. o.attachEvent("on" + type, o._events._callback);
040. } else if (Event._fnIndex(o, type, fn) == -1)
041. queue.push(fn);
042. else return;
043. Event._mem.push([o, type, fn]);
044. };
045. var removeEvent = function (o, type, fn) {
046. var i = Event._fnIndex(o, type, fn);
047. if (i < 0) return;
048. var queue = o._events[type];
049. if (queue.calling) {
050. delete queue[i];
051. if (queue.removeListeners)
052. queue.removeListeners.push(i);
053. else
054. queue.removeListeners = [i];
055. } else
056. if (queue.length == 1)
057. Event._detach(o, type);
058. else
059. queue.splice(i, 1);
060. };
061. var Event = {
062. AT_TARGET: 2,
063. BUBBLING_PHASE: 3,
064. stopPropagation: function () { this.cancelBubble = true },
065. preventDefault: function () { this.returnValue = false },
066. _mem: [],
067. _callListeners: function (e, o) {
068. e.stopPropagation = this.stopPropagation;
069. e.preventDefault = this.preventDefault;
070. e.currentTarget = o;
071. e.target = e.srcElement;
072. e.eventPhase = e.currentTarget == e.target ? this.AT_TARGET : this.BUBBLING_PHASE;
073. switch (e.type) {
074. case "mouseover":
075. e.relatedTarget = e.fromElement;
076. break;
077. case "mouseout":
078. e.relatedTarget = e.toElement;
079. }
080. var queue = o._events[e.type];
081. queue.calling = true;
082. for (var i = 0, l = queue.length; i < l; i++)
083. if (queue[i])
084. if ("handleEvent" in queue[i])
085. queue[i].handleEvent(e);
086. else
087. queue[i].call(o,e);
088. queue.calling = null;
089. if (!queue.removeListeners)
090. return;
091. if (queue.length == queue.removeListeners.length) {
092. this._detach(o, e.type);
093. return;
094. }
095. queue.removeListeners = queue.removeListeners.sort(function(a,b){return a-b});
096. var i = queue.removeListeners.length;
097. while (i--)
098. queue.splice(queue.removeListeners[i], 1);
099. if (queue.length == 0)
100. this._detach(o, e.type);
101. else
102. queue.removeListeners = null;
103. },
104. _detach: function (o, type) {
105. o.detachEvent("on" + type, o._events._callback);
106. delete o._events[type];
107. },
108. _fnIndex: function (o, type, fn) {
109. var queue = o._events[type];
110. if (queue)
111. for (var i = 0, l = queue.length; i < l; i++)
112. if (queue[i] == fn)
113. return i;
114. return -1;
115. },
116. _cleanup: function () {
117. for (var m, i = 0; m = Event._mem[i]; i++)
118. if (m[1] != "unload" || m[2] == Event._cleanup)
119. removeEvent(m[0], m[1], m[2]);
120. }
121. };
122. addEvent(window, "unload", Event._cleanup);
123.} @*/
后来,又发现Dean Edwards也修正了IE事件顺序错乱问题
01.// addEvent/removeEvent written by Dean Edwards, 2005
02.// with input from Tino Zijdel
03.// http://dean.edwards.name/weblog/2005/10/add-event/
04.function addEvent(element, type, handler) {
05. if (!handler.$guid) handler.$guid = addEvent.guid++;
06. if (!element.events) element.events = {};
07. var handlers = element.events[type];
08. if (!handlers) {
09. handlers = element.events[type] = {};
10. if (element["on" + type]) {
11. handlers[0] = element["on" + type];
12. }
13. }
14. handlers[handler.$guid] = handler;
15. element["on" + type] = handleEvent;
16.};
17.addEvent.guid = 1;
18.function removeEvent(element, type, handler) {
19. if (element.events && element.events[type]) {
20. delete element.events[type][handler.$guid];
21. }
22.};
23.function handleEvent(event) {
24. var returnValue = true;
25. event = event || fixEvent(window.event);
26. var handlers = this.events[event.type];
27. for (var i in handlers) {
28. this.$handleEvent = handlers[i];
29. if (this.$handleEvent(event) === false) {
30. returnValue = false;
31. }
32. }
33. return returnValue;
34.};
35.function fixEvent(event) {
36. event.preventDefault = fixEvent.preventDefault;
37. event.stopPropagation = fixEvent.stopPropagation;
38. return event;
39.};
40.fixEvent.preventDefault = function() {
41. this.returnValue = false;
42.};
43.fixEvent.stopPropagation = function() {
44. this.cancelBubble = true;
45.};
function addEvent(element, type, handler) {
if (!handler.$guid) handler.$guid = addEvent.guid++;
if (!element.events) element.events = {};//一个巨大的哈希,
var handlers = element.events[type];
if (!handlers) {
handlers = element.events[type] = {};//哈希的每一个键都是哈希
if (element["on" + type]) {
handlers[0] = element["on" + type];
}
}
handlers[handler.$guid] = handler;
element["on" + type] = function(event) {
var returnValue = true;
event = event || window.event;
var handlers = this.events[event.type];
for (var i in handlers) {
this.$handleEvent = handlers[i];
if (this.$handleEvent(event) === false) {
returnValue = false;
}
}
return returnValue;
};
};
addEvent.guid = 1;
但还是觉得很长,谁有好的主意,拿出来分享下??
赞助商链接