事件模块的演变(3)

上一篇中的add有个问题,对同一类型事件添加多个hanlder时,IE6/7/8下会无序,如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="d1" style="width:200px;height:200px;background:gold;"></div>
<script type="text/javascript">
    var el = document.getElementById('d1');
    function handler1(){alert('1');}
    function handler2(){alert('2');}
    function handler3(){alert('3');}
    function handler4(){alert('4');}
    function handler5(){alert('5');}
    E.add(el, 'click', handler1);
    E.add(el, 'click', handler2);
    E.add(el, 'click', handler3);
    E.add(el, 'click', handler4);
    E.add(el, 'click', handler5);
</script>

IE9/Firefox/Safari/Chomre/Opera会依次输出1,2,3,4,5。但IE6/7/8中则不一定。为解决所有浏览器中多个事件handler有序执行,我们需要一个队列来管理所有的handler。

 

这次,把所有的内部细节封装在一个匿名函数中,该函数执行完毕后返回如上一篇接口相同的方法。另外

  1. 把真正的事件handler挂在el上,即el.listeners,其为一个对象,每一个类型的事件为一个数组,如click为el.listeners["click"] = []
  2. 所有的handler存在在对于的数组中
  3. 删除一个hanlder,将从数组中将其删除
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
E = function(){
    function _isEmptyObj(obj){
        for(var a in obj){
            return false;
        }
        return true;
    }
    function _each(ary, callback){
        for(var i=0,len=ary.length; i<len;){
            callback(i, ary[i]) ? i=0 : i++;
        }
    }
    function _remove(el, type){
        var handler = el.listeners[type]['_handler_'];
        el.removeEventListener ?
            el.removeEventListener(type, handler, false) :
            el.detachEvent('on'+type, handler);
        delete el.listeners[type];
        if(_isEmptyObj(el.listeners)){
            delete el.listeners;
        }
    }
    // 添加事件
    function add(el, type, fn){
        el.listeners = el.listeners || {};
        var listeners = el.listeners[type] = el.listeners[type] || [];
        listeners.push(fn);
        if(!listeners['_handler_']){
            listeners['_handler_'] = function(e){
                var evt = e || window.event;
                for(var i=0,fn; fn=listeners[i++];){
                    fn.call(el, evt);
                }
            }
            el.addEventListener ?
                el.addEventListener(type, listeners['_handler_'], false) :
                el.attachEvent('on' + type,  listeners['_handler_']);
        }
    }
    // 删除事件
    function remove(el, type, fn){
        if(!el.listeners) return;
        var listeners = el.listeners && el.listeners[type];
        if(listeners) {
            _each(listeners, function(i, f){
                if(f==fn){
                    return listeners.splice(i, 1);
                }
            });
            if(listeners.length == 0){
                _remove(el,type);
            }
        }
    }
    //主动触发事件
    function dispatch(el ,type){
        try{
            if(el.dispatchEvent){
                var evt = document.createEvent('Event');
                evt.initEvent(type,true,true);
                el.dispatchEvent(evt);
            }else if(el.fireEvent){
                el.fireEvent('on'+type);
            }
        }catch(e){};
    }  
    return {
        add: add,
        remove: remove,
        dispatch: dispatch
    };
}();

 

相关:

仅IE6/7/8下同一个类型事件的多个handler执行无序 

posted on   snandy  阅读(1702)  评论(3编辑  收藏  举报

编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
< 2011年4月 >
27 28 29 30 31 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
1 2 3 4 5 6 7

统计

点击右上角即可分享
微信分享提示