IE与非IE浏览器在事件绑定的执行顺序问题


原始的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事件时,发现些问题。
 
<!doctype html>
<title>javascript事件绑定  by 司徒正美</title>
<meta charset="utf-8"/>
<meta name="keywords" content="javascript事件绑定 by 司徒正美" />
<meta name="description" content="javascript事件绑定  by 司徒正美" />
<script type="text/javascript">
    function addEvent( obj, type, fn ) {
        if ( obj.attachEvent ) {
            obj["e"+type+fn] = fn;
            obj[type+fn] = function(){obj["e"+type+fn]( window.event );}
            obj.attachEvent("on"+type, obj[type+fn] );
        } else
            obj.addEventListener( type, fn, false );
    }
    window.onload = function(){
        var test = document.getElementById("test");

        addEvent(test,"click",function(){
            alert(1);
        });
        addEvent(test,"click",function(){
            alert(2);
        });
        addEvent(test,"click",function(){
            alert(3);
        });
        addEvent(test,"click",function(){
            alert(4);
        });
    }
</script>
<h1 id="test">javascript事件绑定(点我)</h1>
 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;

  但还是觉得很长,谁有好的主意,拿出来分享下??


« 
» 
快速导航

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3