Вобщем, координальных изменений нет...
Оптимизировал, поймал один баг, немного изименился вызов Add. Код:
var Event=(function(){
var allList=new Array;
var handler=function(evt,index){
if(!evt.fix){
if(!evt)evt=event;
if(!evt.preventDefault)evt.preventDefault=function(){evt.returnValue=false;}
if(!evt.stopPropagation)evt.stopPropagation=function(){evt.cancelBubble=true;}
if(!evt.target)evt.target=(evt.srcElement.nodeType==1)?evt.srcElement:evt.srcElement.parentNode;
if(!evt.relatedTarget&&evt.fromElement)evt.relatedTarget=(evt.fromElement==evt.target)?evt.toElement:evt.fromElement;
if(!evt.which&&evt.button)evt.which=(evt.button&1?1:(evt.button&2?3:(evt.button&4?2:0)));
if(evt.pageX==null&&evt.clientX!=null){
var html=document.documentElement,body=document.body;
evt.pageX=evt.clientX+(html&&html.scrollLeft||body&&body.scrollLeft||0)-(html.clientLeft||0);
evt.pageY=evt.clientY+(html&&html.scrollTop||body&&body.scrollTop||0)-(html.clientTop||0);
}
evt.fix=true;
}
for(var i in allList[index].list[evt.type]){
if(allList[index]&&allList[index].list[evt.type]&&allList[index].list[evt.type][i].call.call(this,evt,allList[index].list[evt.type][i].data)===false){
evt.stopPropagation();
evt.preventDefault();
break;
}
}
}
return{
Add:function(ele,type,call,data){
if(ele.setInterval&&(ele!=window&&!ele.frameElement))ele=window;
for(var i in allList){
if(allList[i].ele==ele){
if(!allList[i].list[type]){
allList[i].list[type]=[{
call:call,
data:obj.data
}];
if(ele.addEventListener)ele.addEventListener(type,allList[i].listener,false);
else if(ele.attachEvent)ele.attachEvent('on'+type,allList[i].listener);
return;
}
for(var c in allList[i].list[type])if(allList[i].list[type][c].call==call)return;
allList[i].list[type].push({
call:call,
data:obj.data
});
return;
}
}
var objListener={
ele:ele,
listener:(function(ele,i){
return function(evt){
handler.call(ele,evt,i);
}
})(ele,allList.length),
list:new Object
}
objListener.list[type]=[{
call:call,
data:data
}];
allList.push(objListener);
if(ele.addEventListener)ele.addEventListener(type,objListener.listener,false);
else if(ele.attachEvent)ele.attachEvent('on'+type,objListener.listener);
},
Del:function(ele,type,call){
for(var i in allList){
if(allList[i].ele==ele){
if(type&&call){
for(var s in allList[i].list[type]){
if(allList[i].list[type][s].call==call){
delete allList[i].list[type][s];
return;
}
}
}else if(type){
ele[type]=null;
delete allList[i].list[type];
}else{
for(var t in allList[i].list){
if(ele.removeEventListener)ele.removeEventListener(t,allList[i].listener,false);
else if(ele.detachEvent)ele.detachEvent('on'+t,allList[i].listener);
}
delete allList[i];
}
return;
}
}
},
Init:function(ele,type){
if(document.createEvent&&ele.dispatchEvent){
var evt=document.createEvent('HTMLEvents');
evt.initEvent(type,true,true);
ele.dispatchEvent(evt);
}else ele.fireEvent(type,event);
}
}
})();
Метод Add: Event.Add(ele,type,call,data); obj - DOM-узел ele. Значение свойства data будет передано в указанный обработчик вторым аргументом. Обработчики будут вызваны в контексте ele. Метод Del не изменился. Если обработчик возвращает false - это не только вызовет методы остановки просачивания и выполнения дефолтных обработок, но и остановит вызовы следующих обработчиков. Я посчитал, что false - это полный stop для события:) На самом деле передача data в обработчик немного увеличила код и кому-то может показаться лишним, но это иногда бывает действительно необходимо. Классический пример:
// Вариант 1
function obj(data){
var _this=this;
this.data=data;
this.call=function(){
alert(_this.data);
}
this.ele=document.createElement('div');
this.ele.onclick=this.call;
}
// Вариант 2
function obj(data){
this.data=data;
this.ele=document.createElement('div');
Event.Add({
ele:this.ele,
data:this
},'click',this.call);
}
obj.prototype.call=function(evt,obj){
alert(obj.data);
}
Какой вариант для вас предпочтительнее?! Примерно из-за такой ситуации я и начал писать библиотеку. |
function obj( var1, var2, ... ){
this.var1 = var1;
this.var2 = var2;
...
this.ele = document.createElement('div');
Event.Add( this.ele, 'click', this.call, var1, var2, ... ); // call
Event.Add( this.ele2, 'click', this.call2, dataArray ); // apply
}
но на самом деле, есть еще варианты. Посмотри, как jQuery находит объекты ($.cache) |
jQuery принимает только 4 параметра...
И потом нужно определять, что передали - 1 массив или +1 данные... Ну может идея с передачей объекта немного замудрена... Я просто не хотел увеличивать количество передаваемых аргументов... Второй вариант (с 4 параметрами) мне кажется предпочтительнее... А что, если я захочу передать именно массив в обработчик (т.е. call)?! Нет, apply тут лишнее, имхо... |
Изменил Add и описание к нему. Прям как jQuery:)
|
apply удобен когда нужно передать данные дальше, т.е. arguments передать нужно в обработчик. Можно пожертвовать возможность передать обработчику массив с одним элементом, тоже являющимся массивом
|
Цитата:
Цитата:
|
function f() {
Event.Add( e, 'click', handler, arguments );
}
f(1, 'asd', true);
|
Ну понятно, как jQuery... Только как мне это прикрутить?! Не соображу...
|
Цитата:
Event.Add( e, 'click', handler, {1, 'asd', true} );
Не буду переделывать... Этот вариант тоже хороший. |
Подниму-ка я ещё разок эту тему;)
Вот... Переделал немного Event:
var Event=(function(){
var allList=new Array;
var falseCall=function(evt){
evt.stopPropagation();
evt.preventDefault();
return false;
}
var handler=function(evt,index){
if(!evt.fix){
if(!evt)evt=event;
if(!evt.preventDefault)evt.preventDefault=function(){evt.returnValue=false;}
if(!evt.stopPropagation)evt.stopPropagation=function(){evt.cancelBubble=true;}
if(!evt.target)evt.target=(evt.srcElement.nodeType==1)?evt.srcElement:evt.srcElement.parentNode;
if(!evt.relatedTarget&&evt.fromElement)evt.relatedTarget=(evt.fromElement==evt.target)?evt.toElement:evt.fromElement;
if(!evt.which&&evt.button)evt.which=(evt.button&1?1:(evt.button&2?3:(evt.button&4?2:0)));
if(evt.pageX==null&&evt.clientX!=null){
var html=document.documentElement,body=document.body;
evt.pageX=evt.clientX+(html&&html.scrollLeft||body&&body.scrollLeft||0)-(html.clientLeft||0);
evt.pageY=evt.clientY+(html&&html.scrollTop||body&&body.scrollTop||0)-(html.clientTop||0);
}
if(typeof(evt.wheelDelta)!=='undefined')evt.detail=-evt.wheelDelta/40;
evt.fix=true;
}
for(var i in allList[index].list[evt.type]){
if(allList[index]&&allList[index].list[evt.type]&&allList[index].list[evt.type][i].call.call(this,evt,allList[index].list[evt.type][i].data)===false){
evt.stopPropagation();
evt.preventDefault();
break;
}
}
}
return{
Add:function(ele,type,call,data){
if(ele.setInterval&&(ele!=window&&!ele.frameElement))ele=window;
for(var i in allList){
if(allList[i].ele==ele){
if(!allList[i].list[type]){
allList[i].list[type]=[{
call:call||falseCall,
data:data
}];
if(ele.addEventListener)ele.addEventListener(type,allList[i].listener,false);
else if(ele.attachEvent)ele.attachEvent('on'+type,allList[i].listener);
return;
}
for(var c in allList[i].list[type])if(allList[i].list[type][c].call==call)return;
allList[i].list[type].push({
call:call||falseCall,
data:data
});
return;
}
}
var objListener={
ele:ele,
listener:(function(ele,i){
return function(evt){
Event.obj=evt;
handler.call(ele,evt,i);
delete Event.obj;
}
})(ele,allList.length),
list:new Object
}
objListener.list[type]=[{
call:call||falseCall,
data:data
}];
allList.push(objListener);
if(ele.addEventListener)ele.addEventListener(type,objListener.listener,false);
else if(ele.attachEvent)ele.attachEvent('on'+type,objListener.listener);
},
Del:function(ele,type,call){
for(var i in allList){
if(allList[i].ele==ele){
var handlers=allList[i].list[type];
if(call&&handlers){
for(var s in handlers){
if(handlers[s].call==call){
handlers.splice(s,1);
if(handlers.length)return;
break;
}
}
}
if(type){
if(ele.removeEventListener)ele.removeEventListener(type,allList[i].listener,false);
else if(ele.detachEvent)ele.detachEvent('on'+type,allList[i].listener);
delete allList[i].list[type];
}
for(var s in allList[i].list)return;
allList.splice(i,1);
return;
}
}
},
Init:function(ele,type){
if(document.createEvent&&ele.dispatchEvent){
var evt=document.createEvent('HTMLEvents');
evt.initEvent(type,true,true);
ele.dispatchEvent(evt);
}else ele.fireEvent(type,event);
}
}
})();
Вобщем, что поменялось: 1. Найден и исправлен серьёзный баг. 2. Теперь запись: Event.Del(ele);не работает. Пока не нашел красивого решения. 3. Немного оптимизировал как объём кода, так и выполнение. 4. Можно передать такие параметры: Event.Add(ele,'click',false);эта запись эквивалентна:
Event.Add(ele,'click',function(evt){return false;})
По-моему очень удобно, ибо не создаются лишние функции:)5. Добавил обработку detail для события onmousewheel в IE. |
| Часовой пояс GMT +3, время: 19:06. |