javascript看qq中多事件绑定的执行顺序

目录 前端技术

事件绑定的执行次序

在W3C的标准下,事件绑定使用的是addEventLisenter。

但微软这家伙经常不按常理出牌。它提供的事件绑定方法是。

关于attachEvent的种种不足,先不一一列举。或许我们已经忍受着用attachEvent来绑定事件。

//object.attachEvent(event, function);

el.attachEvent(‘onclick’, method);

但当在同一元素上绑定多次,你就会知道,微软的这个私人的方法又是多么“不可理喻”。

el.attachEvent(“onclick”, method1);

el.attachEvent(“onclick”, method2);

el.attachEvent(“onclick”, method3);

el.attachEvent(“onclick”, method4);

在各个IE下运行,点击el后,各个方法的执行次序是:

IE6/IE7: method2 -> method4 -> method3 -> method1

IE8: method4 -> method3 -> method2 -> method1

IE9: method1 -> method2 -> method3 -> method4

IE6/7是一种看不出规律的随机执行,IE8是逆序执行,IE9是顺序执行。

无论常识还是W3C标准,这种同一个事件绑定了多个方法的情况,方法的执行次序都应该是先绑定先执行。从IE6-IE9的演变,可以看得出微软还是有在不断改进的。但毕竟各个版本的IE存在,使得我们不得不注意绑定在同一事件上的多个方法之间不要有顺序依赖。

YUI2的事件绑定并没有对执行次序做兼容,如果有些场景的确需要绑定多个方法且方法间需要顺序执行。那我们就只能自己实现了,大致思路是:在先判断绑定的el对象上是否已经同一个事件类型的handlers,如果有则不会重复绑定而是把该对象的handler合并到handlers中成为一个方法,相当于这样function c() { a(); b(); },按照顺序的压入方法实现在IE下不会出现绑定多个方法时能顺序执行。

function addEvent(el, type, handler) {

if (el.attachEvent) { // IE

// 为元素的事件类型创建一个哈希表

el._events = el._events || {};

if (!handler) { return; }

// 取得事件处理函数的数组的引用

var handlers = el._events[type];

if (handlers) {

if(typeof handler._index === ‘undefined’ || handlers[handler._index] !== handler) {

// 将事件处理函数存入数组

handlers.push(handler);

// 为事件处理函数增加索引

handler._index = handlers.length – 1;

}

} else {

// 创建事件处理函数的数组

el._events[type] = [];

// 缓存总的事件绑定函数

el._eventHandlers = function (e) {

e = e || window.event;

var handlers = el._events[type];

// 依次执行所有缓存的事件处理方法

for (var i = 0, len = handlers.length; i

typeof handlers[i] === ‘function’ && handlers[i](e);

}

};

// 绑定一次事件,来处理所有绑定在该事件上的所有函数

el.attachEvent(‘on’ + type, el._eventHandlers);

addEvent(el, type, handler);

}

} else { // 现代浏览器

el.addEventListener(type, handler, false);

}

}

相应的,移除事件的方法也要做一些处理。

function removeEvent(el, type, handler) {

if (el.detachEvent) { // IE

// 取得事件处理函数的数组的引用

var handlers = el._events && el._events[type];

if (handlers) {

if (handler) {

// 删除事件处理函数队列里的函数

delete handlers[handler._index];

// 删除函数的索引

delete handler._index;

if (handlers.length === 0) {

// 解除总的事件绑定

el.detachEvent(‘on’ + type, el._eventHandlers);

}

} else {

// 解除总的事件绑定

el.detachEvent(‘on’ + type, el._eventHandlers);

// 删除该事件绑定上的所有事件处理函数队列

delete el._events[type];

}

}

} else { // 现代浏览器

el.removeEventListener(el, type, handler);

}

}

为了实现各个浏览器下,同一事件绑定多个方法的次序能正确执行。代码上不得不多做一些处理。有兴趣的可以再细致读一下代码,如有问题,欢迎指正。即使无需用到,也需要清楚,绑定在同一事件上的多个方法之间不要有顺序依赖。