Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #271 (permalink)  
Старый 08.10.2009, 10:46
Аватар для B~Vladi
Модератор Всея Форума
Отправить личное сообщение для B~Vladi Посмотреть профиль Найти все сообщения от B~Vladi
 
Регистрация: 14.05.2009
Сообщений: 4,021

Вобщем, координальных изменений нет...
Оптимизировал, поймал один баг, немного изименился вызов 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);
}


Какой вариант для вас предпочтительнее?!
Примерно из-за такой ситуации я и начал писать библиотеку.

Последний раз редактировалось B~Vladi, 08.10.2009 в 12:59.
Ответить с цитированием
  #272 (permalink)  
Старый 08.10.2009, 11:19
Аватар для x-yuri
Отправить личное сообщение для x-yuri Посмотреть профиль Найти все сообщения от x-yuri
 
Регистрация: 27.12.2008
Сообщений: 4,201

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)
Ответить с цитированием
  #273 (permalink)  
Старый 08.10.2009, 11:42
Аватар для B~Vladi
Модератор Всея Форума
Отправить личное сообщение для B~Vladi Посмотреть профиль Найти все сообщения от B~Vladi
 
Регистрация: 14.05.2009
Сообщений: 4,021

jQuery принимает только 4 параметра...
И потом нужно определять, что передали - 1 массив или +1 данные...

Ну может идея с передачей объекта немного замудрена... Я просто не хотел увеличивать количество передаваемых аргументов...

Второй вариант (с 4 параметрами) мне кажется предпочтительнее...
А что, если я захочу передать именно массив в обработчик (т.е. call)?! Нет, apply тут лишнее, имхо...
Ответить с цитированием
  #274 (permalink)  
Старый 08.10.2009, 11:52
Аватар для B~Vladi
Модератор Всея Форума
Отправить личное сообщение для B~Vladi Посмотреть профиль Найти все сообщения от B~Vladi
 
Регистрация: 14.05.2009
Сообщений: 4,021

Изменил Add и описание к нему. Прям как jQuery
Ответить с цитированием
  #275 (permalink)  
Старый 08.10.2009, 11:53
Аватар для x-yuri
Отправить личное сообщение для x-yuri Посмотреть профиль Найти все сообщения от x-yuri
 
Регистрация: 27.12.2008
Сообщений: 4,201

apply удобен когда нужно передать данные дальше, т.е. arguments передать нужно в обработчик. Можно пожертвовать возможность передать обработчику массив с одним элементом, тоже являющимся массивом
Ответить с цитированием
  #276 (permalink)  
Старый 08.10.2009, 11:57
Аватар для B~Vladi
Модератор Всея Форума
Отправить личное сообщение для B~Vladi Посмотреть профиль Найти все сообщения от B~Vladi
 
Регистрация: 14.05.2009
Сообщений: 4,021

Сообщение от x-yuri
apply удобен когда нужно передать данные дальше
Куда дальше?! А так нельзя передать?!
Сообщение от x-yuri
т.е. arguments передать нужно в обработчик
А event куда тогда?!
Ответить с цитированием
  #277 (permalink)  
Старый 08.10.2009, 12:02
Аватар для x-yuri
Отправить личное сообщение для x-yuri Посмотреть профиль Найти все сообщения от x-yuri
 
Регистрация: 27.12.2008
Сообщений: 4,201

function f() {

    Event.Add( e, 'click', handler, arguments );
}
f(1, 'asd', true);
Ответить с цитированием
  #278 (permalink)  
Старый 08.10.2009, 12:29
Аватар для B~Vladi
Модератор Всея Форума
Отправить личное сообщение для B~Vladi Посмотреть профиль Найти все сообщения от B~Vladi
 
Регистрация: 14.05.2009
Сообщений: 4,021

Ну понятно, как jQuery... Только как мне это прикрутить?! Не соображу...

Последний раз редактировалось B~Vladi, 08.10.2009 в 12:38.
Ответить с цитированием
  #279 (permalink)  
Старый 08.10.2009, 13:01
Аватар для B~Vladi
Модератор Всея Форума
Отправить личное сообщение для B~Vladi Посмотреть профиль Найти все сообщения от B~Vladi
 
Регистрация: 14.05.2009
Сообщений: 4,021

Сообщение от x-yuri
function f() {
 
    Event.Add( e, 'click', handler, arguments );
}
f(1, 'asd', true);
Тогда уж проще написать так:
Event.Add( e, 'click', handler, {1, 'asd', true} );

Не буду переделывать... Этот вариант тоже хороший.
Ответить с цитированием
  #280 (permalink)  
Старый 21.10.2009, 11:28
Аватар для B~Vladi
Модератор Всея Форума
Отправить личное сообщение для B~Vladi Посмотреть профиль Найти все сообщения от B~Vladi
 
Регистрация: 14.05.2009
Сообщений: 4,021

Подниму-ка я ещё разок эту тему

Вот... Переделал немного 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.

Последний раз редактировалось B~Vladi, 21.10.2009 в 11:30.
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск